diff --git a/example/chat/certificates/README.md b/example/chat/certificates/README.md new file mode 100644 index 00000000..aef3d092 --- /dev/null +++ b/example/chat/certificates/README.md @@ -0,0 +1,26 @@ +# Certificates + +The certificates in for the examples are generated using the commands shown below. + +Note that this was run on OpenSSL 1.1.1d, of which the arguments can be found in the [OpenSSL Manpages](https://www.openssl.org/docs/man1.1.1/man1), and is not guaranteed to work on different OpenSSL versions. + +```shell +# Extensions required for certificate validation. +$ EXTFILE='extfile.conf' +$ echo 'subjectAltName = IP:127.0.0.1\nbasicConstraints = critical,CA:true' > "${EXTFILE}" + +# Server. +$ SERVER_NAME='server' +$ openssl ecparam -name prime256v1 -genkey -noout -out "${SERVER_NAME}.pem" +$ openssl req -key "${SERVER_NAME}.pem" -new -sha256 -subj '/C=NL' -out "${SERVER_NAME}.csr" +$ openssl x509 -req -in "${SERVER_NAME}.csr" -extfile "${EXTFILE}" -days 365 -signkey "${SERVER_NAME}.pem" -sha256 -out "${SERVER_NAME}.pub.pem" + +# Client. +$ CLIENT_NAME='client' +$ openssl ecparam -name prime256v1 -genkey -noout -out "${CLIENT_NAME}.pem" +$ openssl req -key "${CLIENT_NAME}.pem" -new -sha256 -subj '/C=NL' -out "${CLIENT_NAME}.csr" +$ openssl x509 -req -in "${CLIENT_NAME}.csr" -extfile "${EXTFILE}" -days 365 -CA "${SERVER_NAME}.pub.pem" -CAkey "${SERVER_NAME}.pem" -set_serial '0xabcd' -sha256 -out "${CLIENT_NAME}.pub.pem" + +# Cleanup. +$ rm "${EXTFILE}" "${SERVER_NAME}.csr" "${CLIENT_NAME}.csr" +``` diff --git a/example/chat/certificates/client.pem b/example/chat/certificates/client.pem new file mode 100644 index 00000000..4215b8fa --- /dev/null +++ b/example/chat/certificates/client.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIISoeP9MVCLki8cOM/hyi9/IyCZ3+fxYu+3zHJH4g1fxoAoGCCqGSM49 +AwEHoUQDQgAEQtNPp0zDJDMeoF0EVI1xKqi88b809cn5NDigDKo6ILW0J54/L3GB +LzkXygCQJxcVKsBk4OQB04nBd1TSzzfD0Q== +-----END EC PRIVATE KEY----- diff --git a/example/chat/certificates/client.pub.pem b/example/chat/certificates/client.pub.pem new file mode 100644 index 00000000..2aa6b9d2 --- /dev/null +++ b/example/chat/certificates/client.pub.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBLTCB1aADAgECAgMAq80wCgYIKoZIzj0EAwIwDTELMAkGA1UEBhMCTkwwHhcN +MjQxMTA0MTc0MzI0WhcNMjUxMTA0MTc0MzI0WjANMQswCQYDVQQGEwJOTDBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABELTT6dMwyQzHqBdBFSNcSqovPG/NPXJ+TQ4 +oAyqOiC1tCeePy9xgS85F8oAkCcXFSrAZODkAdOJwXdU0s83w9GjJDAiMA8GA1Ud +EQQIMAaHBH8AAAEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiAw +OWA9hQ/mRt4QjaJoKm2nlWnz+fmhFKcLy4Dko8enPgIgNZbktOO2soA1TxxQJybR +XfbC0srKxi5tx+tCASwj800= +-----END CERTIFICATE----- diff --git a/example/chat/certificates/server.pem b/example/chat/certificates/server.pem new file mode 100644 index 00000000..67e1ece7 --- /dev/null +++ b/example/chat/certificates/server.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIG+1OTeVT3v/OYSBSv5qzM8dO6RNJ8VAGelS54y00dGmoAoGCCqGSM49 +AwEHoUQDQgAEbG8/2ipiuRo8cy3S2PuNskv6vY2GNVamZYP0ZFfrAOOXpIp2WIVA +UkMogtGsnrMFqOoZSic+NfajMBcHX0C5LQ== +-----END EC PRIVATE KEY----- diff --git a/example/chat/certificates/server.pub.pem b/example/chat/certificates/server.pub.pem new file mode 100644 index 00000000..9fd3c30f --- /dev/null +++ b/example/chat/certificates/server.pub.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBNTCB26ADAgECAgkA7SUbA6QFShswCgYIKoZIzj0EAwIwDTELMAkGA1UEBhMC +TkwwHhcNMjQxMTA0MTc0MjUzWhcNMjUxMTA0MTc0MjUzWjANMQswCQYDVQQGEwJO +TDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGxvP9oqYrkaPHMt0tj7jbJL+r2N +hjVWpmWD9GRX6wDjl6SKdliFQFJDKILRrJ6zBajqGUonPjX2ozAXB19AuS2jJDAi +MA8GA1UdEQQIMAaHBH8AAAEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJ +ADBGAiEAlXkUu6xhYeicFSWW/5lVBVH09KOnXAI13dW6FaFIxl4CIQDN8jWod40y +7HpDHkJXwWPfQ9V0TPFczs/mzfMM6a2Ahg== +-----END CERTIFICATE----- diff --git a/example/chat/dial/main.go b/example/chat/dial/main.go index e77ec9c1..34c7e5aa 100644 --- a/example/chat/dial/main.go +++ b/example/chat/dial/main.go @@ -2,9 +2,14 @@ package main import ( "context" + "crypto/x509" + "encoding/pem" + "errors" "flag" "fmt" "net" + "os" + "path/filepath" "github.com/pion/dtls/v3/examples/util" quic "github.com/refraction-networking/uquic" @@ -20,6 +25,13 @@ func main() { addr, err := net.ResolveUDPAddr("udp", *remoteAddr) util.Check(err) + rootCertificate, err := LoadCertificate("certificates/server.pub.pem") + util.Check(err) + certPool := x509.NewCertPool() + cert, err := x509.ParseCertificate(rootCertificate.Certificate[0]) + util.Check(err) + certPool.AddCert(cert) + pconn, err := net.ListenUDP("udp", nil) util.Check(err) quicSpec, err := quic.QUICID2Spec(quic.QUICFirefox_116) @@ -33,8 +45,8 @@ func main() { } econn, err := tp.DialEarly(context.Background(), addr, &tls.Config{ - InsecureSkipVerify: true, - NextProtos: []string{"h3"}, + RootCAs: certPool, + NextProtos: []string{"h3"}, }, &quic.Config{}) util.Check(err) @@ -47,3 +59,38 @@ func main() { util.Chat(stream) } + +// LoadCertificate Load/read certificate(s) from file +func LoadCertificate(path string) (*tls.Certificate, error) { + rawData, err := os.ReadFile(filepath.Clean(path)) + if err != nil { + return nil, err + } + + var certificate tls.Certificate + + for { + block, rest := pem.Decode(rawData) + if block == nil { + break + } + + if block.Type != "CERTIFICATE" { + return nil, errBlockIsNotCertificate + } + + certificate.Certificate = append(certificate.Certificate, block.Bytes) + rawData = rest + } + + if len(certificate.Certificate) == 0 { + return nil, errNoCertificateFound + } + + return &certificate, nil +} + +var ( + errBlockIsNotCertificate = errors.New("block is not a certificate, unable to load certificates") + errNoCertificateFound = errors.New("no certificate found, unable to load certificates") +) diff --git a/example/chat/listen/main.go b/example/chat/listen/main.go index c267264a..467ab9b3 100644 --- a/example/chat/listen/main.go +++ b/example/chat/listen/main.go @@ -4,14 +4,9 @@ package main import ( "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" "encoding/hex" - "encoding/pem" "flag" "fmt" - "math/big" "net" "github.com/pion/dtls/v3/examples/util" @@ -36,6 +31,9 @@ func main() { flag.Parse() + certificate, err := tls.LoadX509KeyPair("certificates/server.pub.pem", "certificates/server.pem") + util.Check(err) + // Prepare the IP to connect to addr, err := net.ResolveUDPAddr("udp", *listenAddr) util.Check(err) @@ -51,7 +49,10 @@ func main() { Conn: pconn, } - listener, err := tp.ListenEarly(generateTLSConfig(), &quic.Config{}) + listener, err := tp.ListenEarly(&tls.Config{ + Certificates: []tls.Certificate{certificate}, + NextProtos: []string{"h3"}, + }, &quic.Config{}) util.Check(err) // Simulate a chat session @@ -82,27 +83,3 @@ func main() { // Start chatting hub.Chat() } - -// Setup a bare-bones TLS config for the server -func generateTLSConfig() *tls.Config { - key, err := rsa.GenerateKey(rand.Reader, 1024) - if err != nil { - panic(err) - } - template := x509.Certificate{SerialNumber: big.NewInt(1)} - certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) - if err != nil { - panic(err) - } - keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) - certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) - - tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) - if err != nil { - panic(err) - } - return &tls.Config{ - Certificates: []tls.Certificate{tlsCert}, - NextProtos: []string{"h3"}, - } -}