Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Go RPC over TLS.You have to create the following keys: certs/client.crt, certs/client.key, certs/server.crt, certs/server.key. client.crt and server.crt should be signed with ca.crt, which should be concatenated to both client.crt and server.crt. It's easier to do with easy-rsa: http://openvpn.net/index.php/open-source/documentation/howto.html#pki
package main
import (
"crypto/tls"
"crypto/x509"
"log"
"net/rpc"
)
func main() {
cert, err := tls.LoadX509KeyPair("certs/client.crt", "certs/client.key")
if err != nil {
log.Fatalf("client: loadkeys: %s", err)
}
if len(cert.Certificate) != 2 {
log.Fatal("client.crt should have 2 concatenated certificates: client + CA")
}
ca, err := x509.ParseCertificate(cert.Certificate[1])
if err != nil {
log.Fatal(err)
}
certPool := x509.NewCertPool()
certPool.AddCert(ca)
config := tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: certPool,
}
conn, err := tls.Dial("tcp", "127.0.0.1:8000", &config)
if err != nil {
log.Fatalf("client: dial: %s", err)
}
defer conn.Close()
log.Println("client: connected to: ", conn.RemoteAddr())
rpcClient := rpc.NewClient(conn)
res := new(Result)
if err := rpcClient.Call("Foo.Bar", "twenty-three", &res); err != nil {
log.Fatal("Failed to call RPC", err)
}
log.Printf("Returned result is %d", res.Data)
}
type Result struct {
Data int
}
package main
import (
"crypto/rand"
"crypto/tls"
"crypto/x509"
//"fmt"
"log"
"net"
"net/rpc"
)
func main() {
if err := rpc.Register(new(Foo)); err != nil {
log.Fatal("Failed to register RPC method")
}
cert, err := tls.LoadX509KeyPair("certs/server.crt", "certs/server.key")
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
if len(cert.Certificate) != 2 {
log.Fatal("server.crt should have 2 concatenated certificates: server + CA")
}
ca, err := x509.ParseCertificate(cert.Certificate[1])
if err != nil {
log.Fatal(err)
}
certPool := x509.NewCertPool()
certPool.AddCert(ca)
config := tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: certPool,
}
config.Rand = rand.Reader
service := "127.0.0.1:8000"
listener, err := tls.Listen("tcp", service, &config)
if err != nil {
log.Fatalf("server: listen: %s", err)
}
log.Print("server: listening")
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("server: accept: %s", err)
break
}
log.Printf("server: accepted from %s", conn.RemoteAddr())
go handleClient(conn)
}
}
func handleClient(conn net.Conn) {
defer conn.Close()
rpc.ServeConn(conn)
log.Println("server: conn: closed")
}
type Foo bool
type Result struct {
Data int
}
func (f *Foo) Bar(args *string, res *Result) error {
res.Data = len(*args)
log.Printf("Received %q, its length is %d", *args, res.Data)
//return fmt.Errorf("Whoops, error happened")
return nil
}
@JayZeeGP

This comment has been minimized.

Show comment
Hide comment
@JayZeeGP

JayZeeGP Jun 30, 2017

I'd like to know which modifications would be needed if there are intermediate certificates. How would the tls.Config change in that case?

JayZeeGP commented Jun 30, 2017

I'd like to know which modifications would be needed if there are intermediate certificates. How would the tls.Config change in that case?

@JalfResi

This comment has been minimized.

Show comment
Hide comment
@JalfResi

JalfResi Oct 19, 2017

Would it be possible to do this with certificates generated with LetsEncrypt?

Would it be possible to do this with certificates generated with LetsEncrypt?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment