添加 github.com/pion/dtls 代码

This commit is contained in:
bjdgyc
2021-05-21 19:03:00 +08:00
parent 54a0cb7928
commit 28b5119f50
380 changed files with 16870 additions and 0 deletions

View File

@@ -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"
```

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIGOO78dEAcepxdUIeDzC28jMcFrJr2q7x+UdhgtJ/RS3oAoGCCqGSM49
AwEHoUQDQgAEGLSNxlkJ9mETKI2Hogq3Cyh06pJKA1YMgcKqYKS6yQQlvvk5rU88
+RojFPgXJukymhfIJmw4eGxxEMSjuEZY7w==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBLTCB1aADAgECAgMAq80wCgYIKoZIzj0EAwIwDTELMAkGA1UEBhMCTkwwHhcN
MjAwMzIwMDk0NjQ0WhcNMjEwMzIwMDk0NjQ0WjANMQswCQYDVQQGEwJOTDBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABBi0jcZZCfZhEyiNh6IKtwsodOqSSgNWDIHC
qmCkuskEJb75Oa1PPPkaIxT4FybpMpoXyCZsOHhscRDEo7hGWO+jJDAiMA8GA1Ud
EQQIMAaHBH8AAAEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiBx
sIkcADN9E60veZOFOeANaRWAiQaLWZfUxqkOmfHztQIgI2CfHMjDQwJZFh35HvFs
NOPJj8wxFhqR5pqMF23cgOY=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDT8Xyx5RpPP+98ulYZKsvKIVdBUJug/L9H2M8JThv+GoAoGCCqGSM49
AwEHoUQDQgAE6Wf0qQqIb5G7g51P83Dh1Yst52kyntGYz1Bt6S7crpmQFs9ZRZMy
bJ6MGIwGcVBMgoL3pfxDKdZ3mnzmoibU0w==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBPzCB5qADAgECAhRtzyVTL+9D0KHfbcKYeKckpLVRmTAKBggqhkjOPQQDAjAN
MQswCQYDVQQGEwJOTDAeFw0yMDAzMjAwOTQ2NDRaFw0yMTAzMjAwOTQ2NDRaMA0x
CzAJBgNVBAYTAk5MMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6Wf0qQqIb5G7
g51P83Dh1Yst52kyntGYz1Bt6S7crpmQFs9ZRZMybJ6MGIwGcVBMgoL3pfxDKdZ3
mnzmoibU06MkMCIwDwYDVR0RBAgwBocEfwAAATAPBgNVHRMBAf8EBTADAQH/MAoG
CCqGSM49BAMCA0gAMEUCIQD000SU+klkNLGvHZcMYNVkCFsImnGKIqPMy3LELSiF
0gIgSGIFkNEIAyNxn44CXZJu3piyz1ouK2fLefDJMYfcXgM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,45 @@
package main
import (
"context"
"fmt"
"net"
"time"
"github.com/pion/dtls/v2"
"github.com/pion/dtls/v2/examples/util"
)
func main() {
// Prepare the IP to connect to
addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}
//
// Everything below is the pion-DTLS API! Thanks for using it ❤️.
//
// Prepare the configuration of the DTLS connection
config := &dtls.Config{
PSK: func(hint []byte) ([]byte, error) {
fmt.Printf("Server's hint: %s \n", hint)
return []byte{0xAB, 0xC1, 0x23}, nil
},
PSKIdentityHint: []byte("Pion DTLS Server"),
CipherSuites: []dtls.CipherSuiteID{dtls.TLS_PSK_WITH_AES_128_CCM_8},
ExtendedMasterSecret: dtls.RequireExtendedMasterSecret,
}
// Connect to a DTLS server
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
dtlsConn, err := dtls.DialWithContext(ctx, "udp", addr, config)
util.Check(err)
defer func() {
util.Check(dtlsConn.Close())
}()
fmt.Println("Connected; type 'exit' to shutdown gracefully")
// Simulate a chat session
util.Chat(dtlsConn)
}

View File

@@ -0,0 +1,47 @@
package main
import (
"context"
"crypto/tls"
"fmt"
"net"
"time"
"github.com/pion/dtls/v2"
"github.com/pion/dtls/v2/examples/util"
"github.com/pion/dtls/v2/pkg/crypto/selfsign"
)
func main() {
// Prepare the IP to connect to
addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}
// Generate a certificate and private key to secure the connection
certificate, genErr := selfsign.GenerateSelfSigned()
util.Check(genErr)
//
// Everything below is the pion-DTLS API! Thanks for using it ❤️.
//
// Prepare the configuration of the DTLS connection
config := &dtls.Config{
Certificates: []tls.Certificate{certificate},
InsecureSkipVerify: true,
ExtendedMasterSecret: dtls.RequireExtendedMasterSecret,
}
// Connect to a DTLS server
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
dtlsConn, err := dtls.DialWithContext(ctx, "udp", addr, config)
util.Check(err)
defer func() {
util.Check(dtlsConn.Close())
}()
fmt.Println("Connected; type 'exit' to shutdown gracefully")
// Simulate a chat session
util.Chat(dtlsConn)
}

View File

@@ -0,0 +1,54 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net"
"time"
"github.com/pion/dtls/v2"
"github.com/pion/dtls/v2/examples/util"
)
func main() {
// Prepare the IP to connect to
addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}
//
// Everything below is the pion-DTLS API! Thanks for using it ❤️.
//
certificate, err := util.LoadKeyAndCertificate("examples/certificates/client.pem",
"examples/certificates/client.pub.pem")
util.Check(err)
rootCertificate, err := util.LoadCertificate("examples/certificates/server.pub.pem")
util.Check(err)
certPool := x509.NewCertPool()
cert, err := x509.ParseCertificate(rootCertificate.Certificate[0])
util.Check(err)
certPool.AddCert(cert)
// Prepare the configuration of the DTLS connection
config := &dtls.Config{
Certificates: []tls.Certificate{*certificate},
ExtendedMasterSecret: dtls.RequireExtendedMasterSecret,
RootCAs: certPool,
}
// Connect to a DTLS server
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
dtlsConn, err := dtls.DialWithContext(ctx, "udp", addr, config)
util.Check(err)
defer func() {
util.Check(dtlsConn.Close())
}()
fmt.Println("Connected; type 'exit' to shutdown gracefully")
// Simulate a chat session
util.Chat(dtlsConn)
}

View File

@@ -0,0 +1,72 @@
package main
import (
"context"
"fmt"
"net"
"time"
"github.com/pion/dtls/v2"
"github.com/pion/dtls/v2/examples/util"
)
func main() {
// Prepare the IP to connect to
addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}
// Create parent context to cleanup handshaking connections on exit.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
//
// Everything below is the pion-DTLS API! Thanks for using it ❤️.
//
// Prepare the configuration of the DTLS connection
config := &dtls.Config{
PSK: func(hint []byte) ([]byte, error) {
fmt.Printf("Client's hint: %s \n", hint)
return []byte{0xAB, 0xC1, 0x23}, nil
},
PSKIdentityHint: []byte("Pion DTLS Client"),
CipherSuites: []dtls.CipherSuiteID{dtls.TLS_PSK_WITH_AES_128_CCM_8},
ExtendedMasterSecret: dtls.RequireExtendedMasterSecret,
// Create timeout context for accepted connection.
ConnectContextMaker: func() (context.Context, func()) {
return context.WithTimeout(ctx, 30*time.Second)
},
}
// Connect to a DTLS server
listener, err := dtls.Listen("udp", addr, config)
util.Check(err)
defer func() {
util.Check(listener.Close())
}()
fmt.Println("Listening")
// Simulate a chat session
hub := util.NewHub()
go func() {
for {
// Wait for a connection.
conn, err := listener.Accept()
util.Check(err)
// defer conn.Close() // TODO: graceful shutdown
// `conn` is of type `net.Conn` but may be casted to `dtls.Conn`
// using `dtlsConn := conn.(*dtls.Conn)` in order to to expose
// functions like `ConnectionState` etc.
// Register the connection with the chat hub
if err == nil {
hub.Register(conn)
}
}
}()
// Start chatting
hub.Chat()
}

View File

@@ -0,0 +1,73 @@
package main
import (
"context"
"crypto/tls"
"fmt"
"net"
"time"
"github.com/pion/dtls/v2"
"github.com/pion/dtls/v2/examples/util"
"github.com/pion/dtls/v2/pkg/crypto/selfsign"
)
func main() {
// Prepare the IP to connect to
addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}
// Generate a certificate and private key to secure the connection
certificate, genErr := selfsign.GenerateSelfSigned()
util.Check(genErr)
// Create parent context to cleanup handshaking connections on exit.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
//
// Everything below is the pion-DTLS API! Thanks for using it ❤️.
//
// Prepare the configuration of the DTLS connection
config := &dtls.Config{
Certificates: []tls.Certificate{certificate},
ExtendedMasterSecret: dtls.RequireExtendedMasterSecret,
// Create timeout context for accepted connection.
ConnectContextMaker: func() (context.Context, func()) {
return context.WithTimeout(ctx, 30*time.Second)
},
}
// Connect to a DTLS server
listener, err := dtls.Listen("udp", addr, config)
util.Check(err)
defer func() {
util.Check(listener.Close())
}()
fmt.Println("Listening")
// Simulate a chat session
hub := util.NewHub()
go func() {
for {
// Wait for a connection.
conn, err := listener.Accept()
util.Check(err)
// defer conn.Close() // TODO: graceful shutdown
// `conn` is of type `net.Conn` but may be casted to `dtls.Conn`
// using `dtlsConn := conn.(*dtls.Conn)` in order to to expose
// functions like `ConnectionState` etc.
// Register the connection with the chat hub
if err == nil {
hub.Register(conn)
}
}
}()
// Start chatting
hub.Chat()
}

View File

@@ -0,0 +1,80 @@
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net"
"time"
"github.com/pion/dtls/v2"
"github.com/pion/dtls/v2/examples/util"
)
func main() {
// Prepare the IP to connect to
addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}
// Create parent context to cleanup handshaking connections on exit.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
//
// Everything below is the pion-DTLS API! Thanks for using it ❤️.
//
certificate, err := util.LoadKeyAndCertificate("examples/certificates/server.pem",
"examples/certificates/server.pub.pem")
util.Check(err)
rootCertificate, err := util.LoadCertificate("examples/certificates/server.pub.pem")
util.Check(err)
certPool := x509.NewCertPool()
cert, err := x509.ParseCertificate(rootCertificate.Certificate[0])
util.Check(err)
certPool.AddCert(cert)
// Prepare the configuration of the DTLS connection
config := &dtls.Config{
Certificates: []tls.Certificate{*certificate},
ExtendedMasterSecret: dtls.RequireExtendedMasterSecret,
ClientAuth: dtls.RequireAndVerifyClientCert,
ClientCAs: certPool,
// Create timeout context for accepted connection.
ConnectContextMaker: func() (context.Context, func()) {
return context.WithTimeout(ctx, 30*time.Second)
},
}
// Connect to a DTLS server
listener, err := dtls.Listen("udp", addr, config)
util.Check(err)
defer func() {
util.Check(listener.Close())
}()
fmt.Println("Listening")
// Simulate a chat session
hub := util.NewHub()
go func() {
for {
// Wait for a connection.
conn, err := listener.Accept()
util.Check(err)
// defer conn.Close() // TODO: graceful shutdown
// `conn` is of type `net.Conn` but may be casted to `dtls.Conn`
// using `dtlsConn := conn.(*dtls.Conn)` in order to to expose
// functions like `ConnectionState` etc.
// Register the connection with the chat hub
hub.Register(conn)
}
}()
// Start chatting
hub.Chat()
}

View File

@@ -0,0 +1,80 @@
package util
import (
"bufio"
"fmt"
"net"
"os"
"strings"
"sync"
)
// Hub is a helper to handle one to many chat
type Hub struct {
conns map[string]net.Conn
lock sync.RWMutex
}
// NewHub builds a new hub
func NewHub() *Hub {
return &Hub{conns: make(map[string]net.Conn)}
}
// Register adds a new conn to the Hub
func (h *Hub) Register(conn net.Conn) {
fmt.Printf("Connected to %s\n", conn.RemoteAddr())
h.lock.Lock()
defer h.lock.Unlock()
h.conns[conn.RemoteAddr().String()] = conn
go h.readLoop(conn)
}
func (h *Hub) readLoop(conn net.Conn) {
b := make([]byte, bufSize)
for {
n, err := conn.Read(b)
if err != nil {
h.unregister(conn)
return
}
fmt.Printf("Got message: %s\n", string(b[:n]))
}
}
func (h *Hub) unregister(conn net.Conn) {
h.lock.Lock()
defer h.lock.Unlock()
delete(h.conns, conn.RemoteAddr().String())
err := conn.Close()
if err != nil {
fmt.Println("Failed to disconnect", conn.RemoteAddr(), err)
} else {
fmt.Println("Disconnected ", conn.RemoteAddr())
}
}
func (h *Hub) broadcast(msg []byte) {
h.lock.RLock()
defer h.lock.RUnlock()
for _, conn := range h.conns {
_, err := conn.Write(msg)
if err != nil {
fmt.Printf("Failed to write message to %s: %v\n", conn.RemoteAddr(), err)
}
}
}
// Chat starts the stdin readloop to dispatch messages to the hub
func (h *Hub) Chat() {
reader := bufio.NewReader(os.Stdin)
for {
msg, err := reader.ReadString('\n')
Check(err)
if strings.TrimSpace(msg) == "exit" {
return
}
h.broadcast([]byte(msg))
}
}

View File

@@ -0,0 +1,154 @@
// Package util provides auxiliary utilities used in examples
package util
import (
"bufio"
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"strings"
)
const bufSize = 8192
var (
errBlockIsNotPrivateKey = errors.New("block is not a private key, unable to load key")
errUnknownKeyTime = errors.New("unknown key time in PKCS#8 wrapping, unable to load key")
errNoPrivateKeyFound = errors.New("no private key found, unable to load key")
errBlockIsNotCertificate = errors.New("block is not a certificate, unable to load certificates")
errNoCertificateFound = errors.New("no certificate found, unable to load certificates")
)
// Chat simulates a simple text chat session over the connection
func Chat(conn io.ReadWriter) {
go func() {
b := make([]byte, bufSize)
for {
n, err := conn.Read(b)
Check(err)
fmt.Printf("Got message: %s\n", string(b[:n]))
}
}()
reader := bufio.NewReader(os.Stdin)
for {
text, err := reader.ReadString('\n')
Check(err)
if strings.TrimSpace(text) == "exit" {
return
}
_, err = conn.Write([]byte(text))
Check(err)
}
}
// Check is a helper to throw errors in the examples
func Check(err error) {
switch e := err.(type) {
case nil:
case (net.Error):
if e.Temporary() {
fmt.Printf("Warning: %v\n", err)
return
}
fmt.Printf("net.Error: %v\n", err)
panic(err)
default:
fmt.Printf("error: %v\n", err)
panic(err)
}
}
// LoadKeyAndCertificate reads certificates or key from file
func LoadKeyAndCertificate(keyPath string, certificatePath string) (*tls.Certificate, error) {
privateKey, err := LoadKey(keyPath)
if err != nil {
return nil, err
}
certificate, err := LoadCertificate(certificatePath)
if err != nil {
return nil, err
}
certificate.PrivateKey = privateKey
return certificate, nil
}
// LoadKey Load/read key from file
func LoadKey(path string) (crypto.PrivateKey, error) {
rawData, err := ioutil.ReadFile(filepath.Clean(path))
if err != nil {
return nil, err
}
block, _ := pem.Decode(rawData)
if block == nil || !strings.HasSuffix(block.Type, "PRIVATE KEY") {
return nil, errBlockIsNotPrivateKey
}
if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
return key, nil
}
if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
switch key := key.(type) {
case *rsa.PrivateKey, *ecdsa.PrivateKey:
return key, nil
default:
return nil, errUnknownKeyTime
}
}
if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil {
return key, nil
}
return nil, errNoPrivateKeyFound
}
// LoadCertificate Load/read certificate(s) from file
func LoadCertificate(path string) (*tls.Certificate, error) {
rawData, err := ioutil.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
}