-
-
Save igorzakhar/33b91317ad5a32e7b244299cfa6021fa to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/ed25519" | |
"crypto/rand" | |
"crypto/tls" | |
"crypto/x509" | |
"crypto/x509/pkix" | |
"fmt" | |
"math/big" | |
"net" | |
"time" | |
) | |
func generateEd25519PrivateKey() (ed25519.PrivateKey, error) { | |
_, k, err := ed25519.GenerateKey(rand.Reader) | |
if err != nil { | |
return nil, err | |
} | |
return k, nil | |
} | |
func generateTLSCertificate(privateKey ed25519.PrivateKey) (*tls.Certificate, error) { | |
now := time.Now() | |
template := &x509.Certificate{ | |
SerialNumber: big.NewInt(now.Unix()), | |
Subject: pkix.Name{ | |
CommonName: "foo", | |
}, | |
NotBefore: now, | |
NotAfter: now.AddDate(1, 0, 0), // one year | |
// TODO no idea what the appropriate values for the following would be | |
BasicConstraintsValid: true, | |
IsCA: true, | |
ExtKeyUsage: []x509.ExtKeyUsage{ | |
x509.ExtKeyUsageServerAuth, | |
}, | |
KeyUsage: x509.KeyUsageKeyEncipherment | | |
x509.KeyUsageDigitalSignature | | |
x509.KeyUsageCertSign, | |
} | |
cert, err := x509.CreateCertificate( | |
rand.Reader, | |
template, | |
template, | |
privateKey.Public(), | |
privateKey, | |
) | |
if err != nil { | |
return nil, err | |
} | |
outCert := &tls.Certificate{ | |
Certificate: [][]byte{ | |
cert, | |
}, | |
PrivateKey: privateKey, | |
} | |
return outCert, nil | |
} | |
func serve() { | |
// generate a new keypair | |
privateKey, err := generateEd25519PrivateKey() | |
if err != nil { | |
fmt.Println("server: could not generate private key, error:", err) | |
return | |
} | |
// generate a certificate from said key | |
tlsCertificate, err := generateTLSCertificate(privateKey) | |
if err != nil { | |
fmt.Println("server: could not generate certificate, error:", err) | |
return | |
} | |
// construct new TLS config with our certificate | |
config := tls.Config{ | |
Certificates: []tls.Certificate{ | |
*tlsCertificate, | |
}, | |
// ClientAuth defines the server's policy in regards to what the client | |
// is expected to provide. | |
// Other options for ClientAuth: | |
// * RequestClientCert | |
// * RequireAnyClientCert | |
// * VerifyClientCertIfGiven | |
// * RequireAndVerifyClientCert | |
ClientAuth: tls.RequestClientCert, | |
// To allow self-signed certificates | |
InsecureSkipVerify: true, | |
} | |
// start a tcp server | |
listener, err := tls.Listen("tcp", "0.0.0.0:1234", &config) | |
if err != nil { | |
fmt.Println("server: could not start listening, error:", err) | |
return | |
} | |
fmt.Println("server: ready") | |
for { | |
// wait for a new incoming connection | |
conn, err := listener.Accept() | |
if err != nil { | |
fmt.Println("server: could not accept incoming connection, error:", err) | |
continue | |
} | |
// we got a connection | |
fmt.Println("server: accepted connection from", conn.RemoteAddr()) | |
// get the underlying tls connection | |
tlsConn, ok := conn.(*tls.Conn) | |
if !ok { | |
fmt.Println("server: erm, this is not a tls conn") | |
return | |
} | |
// perform handshake | |
if err := tlsConn.Handshake(); err != nil { | |
fmt.Println("client: error during handshake, error:", err) | |
return | |
} | |
// get connection state and print some stuff | |
state := tlsConn.ConnectionState() | |
for _, v := range state.PeerCertificates { | |
fmt.Printf( | |
"server: remote public key: %x\n", | |
v.PublicKey, | |
) | |
} | |
// close connection | |
conn.Close() | |
} | |
} | |
func dial() { | |
// generate a new keypair | |
privateKey, err := generateEd25519PrivateKey() | |
if err != nil { | |
fmt.Println("server: Could not generate private key, error:", err) | |
return | |
} | |
// generate a certificate from said key | |
tlsCertificate, err := generateTLSCertificate(privateKey) | |
if err != nil { | |
fmt.Println("server: Could not generate certificate, error:", err) | |
return | |
} | |
// construct new TLS config with our certificate | |
config := tls.Config{ | |
Certificates: []tls.Certificate{ | |
*tlsCertificate, | |
}, | |
// To allow self-signed certificates | |
InsecureSkipVerify: true, | |
} | |
// constrct a new dialer | |
dialer := net.Dialer{ | |
Timeout: time.Second, | |
} | |
// dial using our new dialer | |
tlsConn, err := tls.DialWithDialer(&dialer, "tcp", "0.0.0.0:1234", &config) | |
if err != nil { | |
fmt.Println("client: could not dial, error:", err) | |
return | |
} | |
// we got a connection | |
fmt.Println("client: connected to", tlsConn.RemoteAddr()) | |
// perform handshake | |
if err := tlsConn.Handshake(); err != nil { | |
fmt.Println("client: error during handshake, error:", err) | |
return | |
} | |
// get connection state and print some stuff | |
state := tlsConn.ConnectionState() | |
for _, v := range state.PeerCertificates { | |
fmt.Printf( | |
"client: remote public key: %x\n", | |
v.PublicKey, | |
) | |
} | |
// close connection | |
tlsConn.Close() | |
} | |
func main() { | |
go serve() | |
dial() | |
time.Sleep(time.Second) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment