Last active
November 9, 2023 08:43
-
-
Save geoah/31340b8155318a3661b1555c191470b5 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
// TODO no idea what the appropriate values for the following would be
The BasicConstraintsValid is for setting 'pathLenConstraint' on the certificate. When true it will be set, otherwise its left unset.
For a self signed, it doesn't make much difference. For a root CA or Inter CA it governs if that CA can issue other CAs.
When isCA is true, MaxPathLen and MaxPathLenZero all control that constraint.
if MaxPathLen = 0, default, The CA can only issue non CA's (server/client certs etc)
When > 0, it can issue intermediate CA's, which can issue their own certs.