Giter VIP home page Giter VIP logo

dtls's Introduction


Pion DTLS

A Go implementation of DTLS

Pion DTLS Sourcegraph Widget Slack Widget
GitHub Workflow Status Go Reference Coverage Status Go Report Card License: MIT


Native DTLS 1.2 implementation in the Go programming language.

A long term goal is a professional security review, and maybe an inclusion in stdlib.

RFCs

Implemented

Goals/Progress

This will only be targeting DTLS 1.2, and the most modern/common cipher suites. We would love contributions that fall under the 'Planned Features' and any bug fixes!

Current features

  • DTLS 1.2 Client/Server
  • Key Exchange via ECDHE(curve25519, nistp256, nistp384) and PSK
  • Packet loss and re-ordering is handled during handshaking
  • Key export (RFC 5705)
  • Serialization and Resumption of sessions
  • Extended Master Secret extension (RFC 7627)
  • ALPN extension (RFC 7301)

Supported ciphers

ECDHE
  • TLS_ECDHE_ECDSA_WITH_AES_128_CCM (RFC 6655)
  • TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (RFC 6655)
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (RFC 5289)
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (RFC 5289)
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (RFC 5289)
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (RFC 5289)
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (RFC 8422)
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (RFC 8422)
PSK
ECDHE & PSK
  • TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 (RFC 5489)

Planned Features

  • Chacha20Poly1305

Excluded Features

  • DTLS 1.0
  • Renegotiation
  • Compression

Using

This library needs at least Go 1.13, and you should have Go modules enabled.

Pion DTLS

For a DTLS 1.2 Server that listens on 127.0.0.1:4444

go run examples/listen/selfsign/main.go

For a DTLS 1.2 Client that connects to 127.0.0.1:4444

go run examples/dial/selfsign/main.go

OpenSSL

Pion DTLS can connect to itself and OpenSSL.

  // Generate a certificate
  openssl ecparam -out key.pem -name prime256v1 -genkey
  openssl req -new -sha256 -key key.pem -out server.csr
  openssl x509 -req -sha256 -days 365 -in server.csr -signkey key.pem -out cert.pem

  // Use with examples/dial/selfsign/main.go
  openssl s_server -dtls1_2 -cert cert.pem -key key.pem -accept 4444

  // Use with examples/listen/selfsign/main.go
  openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug -cert cert.pem -key key.pem

Using with PSK

Pion DTLS also comes with examples that do key exchange via PSK

Pion DTLS

go run examples/listen/psk/main.go
go run examples/dial/psk/main.go

OpenSSL

  // Use with examples/dial/psk/main.go
  openssl s_server -dtls1_2 -accept 4444 -nocert -psk abc123 -cipher PSK-AES128-CCM8

  // Use with examples/listen/psk/main.go
  openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -psk abc123 -cipher PSK-AES128-CCM8

Community

Pion has an active community on the Slack.

Follow the Pion Twitter for project updates and important WebRTC news.

We are always looking to support your projects. Please reach out if you have something to build! If you need commercial support or don't want to use public methods you can contact us at [email protected]

Contributing

Check out the contributing wiki to join the group of amazing people making this project possible

License

MIT License - see LICENSE for full text

dtls's People

Contributors

arlolra avatar at-wat avatar backkem avatar bocajim avatar boks1971 avatar carsonhoffman avatar cnderrauber avatar cohosh avatar daenney avatar enobufs avatar ernado avatar fffilimonov avatar hasheddan avatar hugoarregui avatar igolaizola avatar itviewer avatar jdbruijn avatar jech avatar jinleileiking avatar jkralik avatar kevmo314 avatar pionbot avatar renovate-bot avatar renovate[bot] avatar rumpelsepp avatar sean-der avatar snawoot avatar stv0g avatar sukunrt avatar taoso avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dtls's Issues

pion/dtls only supports DTLS v1.2 and doesn't properly handle exiting on older versions

Your environment.

  • Version: [email protected]
  • Browser: echo show
  • Other Information - I am new to TLS but here's my findings now. According to [RFC5246 7.4.3][https://tools.ietf.org/html/rfc5246#section-7.4.3] it's not legal to send ServerKeyExchange message for RSA while pion/dtls keeps waiting for ServerKeyExchange message in flight3 of client_handlers.go

What did you do?

What did you expect?

What happened?

Support multiple certificates and certificate chains

Your environment.

Library usage

	dtlsConfig := &dtls.Config{
		Certificate: certificate,
		PrivateKey:  privateKey,
		ClientAuth:  dtls.RequestClientCert,
	}

	trackingContext := NewTrackingContext()

	listener, err := dtls.Listen("udp", bindAddr, dtlsConfig)
	if err != nil {
		logger.Fatal(err)
	}
	defer listener.Close()

	for {
		logger.Debug("Waiting for the new connection")
		conn, err := listener.Accept()
		if err != nil {
			logger.Debugf("Failed to accept a new connection: %s", err)
		}
		go communicate(conn.(*dtls.Conn), trackingContext)
	}

What did you do?

I tried to connect to the simple dtls server using

openssl s_client -dtls1_2 -cert cert.pem -key cert.key -mtu 1472 127.0.0.1:8080

and it works! But when I use a -cert_chain argument, dtls implementation fails:

openssl s_client -dtls1_2 -cert cert.pem -cert_chain cert.pem -key cert.key -mtu 1472 127.0.0.1:8080

What did you expect?

Successful handshake

What happened?

Logs from server implementation on golang:

2019-04-05T15:09:23.968+0300    DEBUG   signaling       signaling/main.go:167   Waiting for the new connection
2019-04-05T15:09:23.968+0300    DEBUG   signaling       signaling/main.go:47    Accepted a new connection from 127.0.0.1:37854
2019-04-05T15:09:23.968+0300    DEBUG   signaling       signaling/main.go:56    Read error: dtls: data length and declared length do not match
handleIncoming: Handshake not finished, dropping packet

image

Support TLS_PSK_WITH_AES_128_GCM_SHA256 (Philips Hue Entertainment API)

In the same spirit as #45, I'd like to add support for TLS_PSK_WITH_AES_128_GCM_SHA256 which is what Philips uses for the new Hue Entertainment API.

Given we already have PSK support thanks to @Sean-Der's efforts on #45, #76 and we already have AES_128_GCM_SHA256 I suspect this should be relatively straightforward.

I'll take a look at this in the coming weeks, just wanted to file an issue here so it's tracked somewhere.

Extended Master Secret support [RFC7627]

Summary

We wish to add support for the "Extended Master Secret" extension as recommended by RFC7627

Motivation

Some dTLS clients use the "Extended Master Secret" extension in the Client Hello message. Per the RFC7627 spec, if the client requests "Extended Master Secret" the server must also specify supporting "Extended Master Secret" in the Server Hello message. If the server does not, then it is recommended that the client must close the connection and some clients do in fact do this.

What this means in effect, that some dTLS are unable to communicate with a pion/dtls server without this extension support.

Describe alternatives you've considered

It would be possible to disable "Extended Master Secret" extension in these clients, but increases security risks as describe in RFC7627.

Client example error - Expected and actual key signature do not match

Hello.

Following the instructions in the readme to create a certificate and key and testing out the client example, I get the following error with the latest version of the library (as of today):

$ go run examples/dial/main.go 
panic: dtls: Expected and actual key signature do not match

goroutine 1 [running]:
github.com/pions/dtls/examples/util.Check(...)
	/home/vagrant/dtls/examples/util/util.go:41
main.main()
	/home/vagrant/dtls/examples/dial/main.go:28 +0x27d
exit status 2

I'm on CentOS 7. My OpenSSL version is 1.0.2k-fips, and I'm on Go 1.11.2.

Implement more cipher suites

The following are in the ClientHello from Chrome.

I wouldn't implement anything weaker then what we have now. However CHACHA20_POLY1305 is a good candidate.

Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)

Add benchmark for throughput

Summary

Implement benchmark via standard go *testing.B for throughput.
Probably, multiple ones: per-packet size and (maybe) per cipher suites, with multiple concurrency level, etc.

Motivation

This will allow us to track performance between different commits and versions.

Note that no packet loss simulation or any other side-effects are expected for this iteration, only raw performance in ideal situation.

Race in closing c.decrypted

==================
WARNING: DATA RACE
Write at 0x00c000024f70 by goroutine 46:
  runtime.closechan()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/runtime/chan.go:327 +0x0
  github.com/pions/dtls/pkg/dtls.(*Conn).stopWithError()
      /home/travis/gopath/src/github.com/pions/dtls/pkg/dtls/conn.go:392 +0x115
  github.com/pions/dtls/pkg/dtls.(*Conn).Close()
      /home/travis/gopath/src/github.com/pions/dtls/pkg/dtls/conn.go:196 +0x79
  github.com/pions/webrtc/internal/sctp.(*Association).Close()
      /home/travis/gopath/src/github.com/pions/webrtc/internal/sctp/association.go:174 +0x71
  github.com/pions/webrtc/internal/network.(*Manager).Close()
      /home/travis/gopath/src/github.com/pions/webrtc/internal/network/manager.go:253 +0x304
  github.com/pions/webrtc.(*RTCPeerConnection).Close()
      /home/travis/gopath/src/github.com/pions/webrtc/rtcpeerconnection.go:1080 +0xdd
  github.com/pions/webrtc.TestRTCPeerConnection_Close()
      /home/travis/gopath/src/github.com/pions/webrtc/rtcpeerconnection_close_test.go:48 +0x359
  testing.tRunner()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/testing/testing.go:827 +0x162
Previous read at 0x00c000024f70 by goroutine 67:
  runtime.chansend()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/runtime/chan.go:140 +0x0
  github.com/pions/dtls/pkg/dtls.(*Conn).handleIncomingPacket()
      /home/travis/gopath/src/github.com/pions/dtls/pkg/dtls/conn.go:327 +0x439
  github.com/pions/dtls/pkg/dtls.(*Conn).handleIncoming()
      /home/travis/gopath/src/github.com/pions/dtls/pkg/dtls/conn.go:272 +0xde
  github.com/pions/dtls/pkg/dtls.createConn.func1()
      /home/travis/gopath/src/github.com/pions/dtls/pkg/dtls/conn.go:120 +0x128
Goroutine 46 (running) created at:
  testing.(*T).Run()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/testing/testing.go:878 +0x659
  testing.runTests.func1()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/testing/testing.go:1119 +0xa8
  testing.tRunner()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/testing/testing.go:827 +0x162
  testing.runTests()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/testing/testing.go:1117 +0x4ee
  testing.(*M).Run()
      /home/travis/.gimme/versions/go1.11.4.linux.amd64/src/testing/testing.go:1034 +0x2ee
  main.main()
      _testmain.go:512 +0x342
Goroutine 67 (running) created at:
  github.com/pions/dtls/pkg/dtls.createConn()
      /home/travis/gopath/src/github.com/pions/dtls/pkg/dtls/conn.go:109 +0x635
  github.com/pions/dtls/pkg/dtls.Client()
      /home/travis/gopath/src/github.com/pions/dtls/pkg/dtls/conn.go:142 +0x70
  github.com/pions/webrtc/internal/network.(*Manager).startDTLS()
      /home/travis/gopath/src/github.com/pions/webrtc/internal/network/manager.go:183 +0x864
  github.com/pions/webrtc/internal/network.(*Manager).Start()
      /home/travis/gopath/src/github.com/pions/webrtc/internal/network/manager.go:115 +0x332
  github.com/pions/webrtc.(*RTCPeerConnection).SetRemoteDescription.func1()
      /home/travis/gopath/src/github.com/pions/webrtc/rtcpeerconnection.go:738 +0x195

Phase out internal/ice

Phase out internal/ice and find an alternative way to show off the Server and Client examples.

Protect sensitive memory regions separately

Summary

This is for a discussion around protecting sensitive portions of memory (i.e. handshake cache, master secret, private keys) instead of leaving it with the same regular Golang memory handling.

One such implementation could be to use something like memguard which utilizes kernel features to more carefully protect certain portions of memory.

Motivation

The motivation is to minimize existential risk of vulnerabilities in the application, Golang, or other lower level systems that could allow sensitive memory to be read given some set of vulnerabilities that allow for the situation to occur.

Describe alternatives you've considered

The primary alternative is to rely on Golang's tried and true memory functions and to audit and implement for best practices to ensure sensitive struct members are isolated and private, and sensitive memory is as short lived as possible

Additional context

We could consider introducing a dependency on https://godoc.org/github.com/awnumar/memguard, for creating a secure enclave where we store sensitive information. It's a little more extreme than just zeroing out a buffer but it goes to fairly great lengths to help you keep a memory area protected.

Originally posted by @daenney in #93

Slice bounds out of range

Your environment.

  • Version: v1.5.0
  • Browser: Firefox 68.0.1
  • Other Information - stacktraces, related issues, suggestions how to fix, links for us to have context
panic: runtime error: slice bounds out of range

goroutine 1490 [running]:
github.com/pion/dtls.unpackDatagram(0xc0006a0000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0, 0x0, 0x0)
        /home/paul/go/pkg/mod/github.com/pion/[email protected]/record_layer.go:84 +0x227
github.com/pion/dtls.(*Conn).inboundLoop(0xc000091b80)
        /home/paul/go/pkg/mod/github.com/pion/[email protected]/conn.go:353 +0x150
created by github.com/pion/dtls.createConn
        /home/paul/go/pkg/mod/github.com/pion/[email protected]/conn.go:170 +0x619

What did you do?

It looks like it just occurs when a peer connects. I can't cause this to reproduce, but it does seem to happen once in a while. It could either be caused by a Firefox client or a client using the NPM wrtc library (latest ver.)

What did you expect?

No panic.

What happened?

Panics

Race found with isInitialized

=== RUN   TestPionE2ELossy
==================
WARNING: DATA RACE
Read at 0x00c0002485c0 by goroutine 42:
  github.com/pion/dtls.(*cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256).isInitialized()
      <autogenerated>:1 +0x4f
  github.com/pion/dtls.(*Conn).handleIncomingPacket()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:415 +0x13c8
  github.com/pion/dtls.(*Conn).inboundLoop()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:389 +0x2cb
Previous write at 0x00c0002485c0 by goroutine 41:
  github.com/pion/dtls.(*cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256).init()
      /home/travis/gopath/src/github.com/pion/dtls/cipher_suite_tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go:50 +0x32b
  github.com/pion/dtls.initalizeCipherSuite()
      /home/travis/gopath/src/github.com/pion/dtls/client_handlers.go:36 +0x4b6
  github.com/pion/dtls.clientFlightHandler()
      /home/travis/gopath/src/github.com/pion/dtls/client_handlers.go:385 +0x1519
  github.com/pion/dtls.(*Conn).startHandshakeOutbound.func1()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:523 +0x45a
Goroutine 42 (running) created at:
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:188 +0xf67
  github.com/pion/dtls.Client()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:224 +0x14c
  github.com/pion/dtls/e2e.TestPionE2ELossy.func1()
      /home/travis/gopath/src/github.com/pion/dtls/e2e/e2e_lossy_test.go:101 +0x12b
Goroutine 41 (running) created at:
  github.com/pion/dtls.(*Conn).startHandshakeOutbound()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:512 +0x68
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:185 +0xf42
  github.com/pion/dtls.Client()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:224 +0x14c
  github.com/pion/dtls/e2e.TestPionE2ELossy.func1()
      /home/travis/gopath/src/github.com/pion/dtls/e2e/e2e_lossy_test.go:101 +0x12b
==================
==================
WARNING: DATA RACE
Read at 0x00c000304538 by goroutine 42:
  github.com/pion/dtls.(*cryptoGCM).decrypt()
      /home/travis/gopath/src/github.com/pion/dtls/crypto_gcm.go:83 +0x12e
  github.com/pion/dtls.(*cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256).decrypt()
      /home/travis/gopath/src/github.com/pion/dtls/cipher_suite_tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go:71 +0x184
  github.com/pion/dtls.(*Conn).handleIncomingPacket()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:421 +0x1161
  github.com/pion/dtls.(*Conn).inboundLoop()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:389 +0x2cb
Previous write at 0x00c000304538 by goroutine 41:
  github.com/pion/dtls.newCryptoGCM()
      /home/travis/gopath/src/github.com/pion/dtls/crypto_gcm.go:43 +0x2fa
  github.com/pion/dtls.(*cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256).init()
      /home/travis/gopath/src/github.com/pion/dtls/cipher_suite_tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go:50 +0x2f3
  github.com/pion/dtls.initalizeCipherSuite()
      /home/travis/gopath/src/github.com/pion/dtls/client_handlers.go:36 +0x4b6
  github.com/pion/dtls.clientFlightHandler()
      /home/travis/gopath/src/github.com/pion/dtls/client_handlers.go:385 +0x1519
  github.com/pion/dtls.(*Conn).startHandshakeOutbound.func1()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:523 +0x45a
Goroutine 42 (running) created at:
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:188 +0xf67
  github.com/pion/dtls.Client()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:224 +0x14c
  github.com/pion/dtls/e2e.TestPionE2ELossy.func1()
      /home/travis/gopath/src/github.com/pion/dtls/e2e/e2e_lossy_test.go:101 +0x12b
Goroutine 41 (running) created at:
  github.com/pion/dtls.(*Conn).startHandshakeOutbound()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:512 +0x68
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:185 +0xf42
  github.com/pion/dtls.Client()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:224 +0x14c
  github.com/pion/dtls/e2e.TestPionE2ELossy.func1()
      /home/travis/gopath/src/github.com/pion/dtls/e2e/e2e_lossy_test.go:101 +0x12b
==================
==================
WARNING: DATA RACE
Read at 0x00c000384364 by goroutine 42:
  runtime.slicecopy()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/runtime/slice.go:197 +0x0
  github.com/pion/dtls.(*cryptoGCM).decrypt()
      /home/travis/gopath/src/github.com/pion/dtls/crypto_gcm.go:83 +0x187
  github.com/pion/dtls.(*cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256).decrypt()
      /home/travis/gopath/src/github.com/pion/dtls/cipher_suite_tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go:71 +0x184
  github.com/pion/dtls.(*Conn).handleIncomingPacket()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:421 +0x1161
  github.com/pion/dtls.(*Conn).inboundLoop()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:389 +0x2cb
Previous write at 0x00c000384360 by goroutine 41:
  runtime.slicecopy()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/runtime/slice.go:197 +0x0
  github.com/pion/dtls.prfPHash()
      /home/travis/gopath/src/github.com/pion/dtls/prf.go:146 +0x203
  github.com/pion/dtls.prfEncryptionKeys()
      /home/travis/gopath/src/github.com/pion/dtls/prf.go:164 +0x25b
  github.com/pion/dtls.(*cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256).init()
      /home/travis/gopath/src/github.com/pion/dtls/cipher_suite_tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go:44 +0x123
  github.com/pion/dtls.initalizeCipherSuite()
      /home/travis/gopath/src/github.com/pion/dtls/client_handlers.go:36 +0x4b6
  github.com/pion/dtls.clientFlightHandler()
      /home/travis/gopath/src/github.com/pion/dtls/client_handlers.go:385 +0x1519
  github.com/pion/dtls.(*Conn).startHandshakeOutbound.func1()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:523 +0x45a
Goroutine 42 (running) created at:
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:188 +0xf67
  github.com/pion/dtls.Client()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:224 +0x14c
  github.com/pion/dtls/e2e.TestPionE2ELossy.func1()
      /home/travis/gopath/src/github.com/pion/dtls/e2e/e2e_lossy_test.go:101 +0x12b
Goroutine 41 (running) created at:
  github.com/pion/dtls.(*Conn).startHandshakeOutbound()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:512 +0x68
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:185 +0xf42
  github.com/pion/dtls.Client()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:224 +0x14c
  github.com/pion/dtls/e2e.TestPionE2ELossy.func1()
      /home/travis/gopath/src/github.com/pion/dtls/e2e/e2e_lossy_test.go:101 +0x12b
==================

Race in serverFlightHandler

Your environment.

What happened?

Aside from the test getting stuck we're seeing the following race in SubtestStress50Conn10Stream50Msg:

==================
WARNING: DATA RACE
Read at 0x00c00433c870 by goroutine 1065:
  github.com/pion/dtls.serverFlightHandler()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/server_handlers.go:386 +0x710
  github.com/pion/dtls.(*Conn).handleIncomingPacket()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:330 +0xdc1
  github.com/pion/dtls.(*Conn).handleIncoming()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:314 +0xd8
  github.com/pion/dtls.createConn.func1()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:146 +0x174
Previous write at 0x00c00433c870 by goroutine 1064:
  github.com/pion/dtls.serverFlightHandler()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/server_handlers.go:401 +0xbef
  github.com/pion/dtls.(*Conn).startHandshakeOutbound.func1()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:434 +0x208
Goroutine 1065 (running) created at:
  github.com/pion/dtls.createConn()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:131 +0x921
  github.com/pion/webrtc/v2.(*DTLSTransport).Start()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:176 +0x815
  github.com/pion/webrtc/v2.(*PeerConnection).SetRemoteDescription.func2()
      /home/travis/gopath/pkg/mod/github.com/pion/webrtc/[email protected]/peerconnection.go:909 +0x36f
Goroutine 1064 (running) created at:
  github.com/pion/dtls.(*Conn).startHandshakeOutbound()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:422 +0x4c
  github.com/pion/dtls.createConn()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:128 +0x8fc
  github.com/pion/webrtc/v2.(*DTLSTransport).Start()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:176 +0x815
  github.com/pion/webrtc/v2.(*PeerConnection).SetRemoteDescription.func2()
      /home/travis/gopath/pkg/mod/github.com/pion/webrtc/[email protected]/peerconnection.go:909 +0x36f
==================

Noteworthy about this test is that it opens multiple PeerConnections in parallel.

End handshake

Add a good way to end the handshake. At the moment the server sends handshake finished messages forever.

Implement handshake rollback handling

We need to handle the remote peer losing some of our packets.

IE if we get a serverHello and are in flight 5 we should rollback to flight3. This is the other side telling us they missed some of our messages.

We should also write a integration test around this. We should generate/capture some packets from OpenSSL to verify and make sure the rollback behavior doesn't regress.


I would also move the timer logic here one level higher since it is duplicated in both the client/server

Add E2E tests with OpenSSL

Add some basic testing using s_client + s_server

The author should also refactor/re-use our existing E2E testing code so that we don't duplicate in both places.

Race condition found with insecureSkipVerify

==================
WARNING: DATA RACE
Write at 0x00c0000906a8 by goroutine 8:
  github.com/pion/dtls.testClient()
      /home/travis/gopath/src/github.com/pion/dtls/conn_test.go:115 +0x55
  github.com/pion/dtls.TestSimpleReadWrite()
      /home/travis/gopath/src/github.com/pion/dtls/bench_test.go:39 +0x311
  testing.tRunner()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:865 +0x163
Previous read at 0x00c0000906a8 by goroutine 9:
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:124 +0x7fd
  github.com/pion/dtls.Server()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:215 +0x14c
  github.com/pion/dtls.testServer()
      /home/travis/gopath/src/github.com/pion/dtls/conn_test.go:128 +0x65
  github.com/pion/dtls.TestSimpleReadWrite.func1()
      /home/travis/gopath/src/github.com/pion/dtls/bench_test.go:27 +0x72
Goroutine 8 (running) created at:
  testing.(*T).Run()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:916 +0x65a
  testing.runTests.func1()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:1157 +0xa8
  testing.tRunner()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:865 +0x163
  testing.runTests()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:1155 +0x523
  testing.(*M).Run()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:1072 +0x2eb
  main.main()
      _testmain.go:304 +0x344
Goroutine 9 (running) created at:
  github.com/pion/dtls.TestSimpleReadWrite()
      /home/travis/gopath/src/github.com/pion/dtls/bench_test.go:26 +0x2e4
  testing.tRunner()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:865 +0x163
==================

Race detected in dtls

Found this while debugging unrelated issues with webrtc (at the end of the webrtc testibility branch)

It's not easy to reproduce

==================
WARNING: DATA RACE
Write at 0x00c0002f204c by goroutine 44:
  github.com/pions/dtls/pkg/dtls.(*Conn).handleIncomingPacket()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:332 +0x2b0
  github.com/pions/dtls/pkg/dtls.(*Conn).handleIncoming()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:279 +0xde
  github.com/pions/dtls/pkg/dtls.createConn.func1()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:124 +0x149

Previous read at 0x00c0002f204c by goroutine 43:
  github.com/pions/dtls/pkg/dtls.clientFlightHandler()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/client_handlers.go:168 +0xc63
  github.com/pions/dtls/pkg/dtls.(*Conn).startHandshakeOutbound.func1()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:381 +0x202

Goroutine 44 (running) created at:
  github.com/pions/dtls/pkg/dtls.createConn()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:109 +0x635
  github.com/pions/dtls/pkg/dtls.Client()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:146 +0x70
  github.com/pions/webrtc.(*RTCDtlsTransport).Start()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/webrtc/rtcdtlstransport.go:110 +0x2b9
  github.com/pions/webrtc.(*testORTCStack).setSignal()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/webrtc/rtcdatachannel_ortc_test.go:102 +0x227
  github.com/pions/webrtc.signalORTCPair.func1()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/webrtc/rtcdatachannel_ortc_test.go:221 +0x47

Goroutine 43 (running) created at:
  github.com/pions/dtls/pkg/dtls.(*Conn).startHandshakeOutbound()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:369 +0x4c
  github.com/pions/dtls/pkg/dtls.createConn()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:106 +0x613
  github.com/pions/dtls/pkg/dtls.Client()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/dtls/pkg/dtls/conn.go:146 +0x70
  github.com/pions/webrtc.(*RTCDtlsTransport).Start()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/webrtc/rtcdtlstransport.go:110 +0x2b9
  github.com/pions/webrtc.(*testORTCStack).setSignal()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/webrtc/rtcdatachannel_ortc_test.go:102 +0x227
  github.com/pions/webrtc.signalORTCPair.func1()
      /home/wdouglass/Source/CRL/2020/vidserv/src/github.com/pions/webrtc/rtcdatachannel_ortc_test.go:221 +0x47
==================

Race in handshake_message_finished

Your environment.

What happened?

Aside from the test getting stuck we're seeing the following race in SubtestStress50Conn10Stream50Msg:

==================
WARNING: DATA RACE
Read at 0x00c003731800 by goroutine 1065:
  runtime.slicecopy()
      /home/travis/.gimme/versions/go1.12.3.linux.amd64/src/runtime/slice.go:197 +0x0
  github.com/pion/dtls.(*handshakeMessageFinished).Marshal()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/handshake_message_finished.go:12 +0xae
  github.com/pion/dtls.(*handshake).Marshal()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/handshake.go:81 +0xbb
  github.com/pion/dtls.(*recordLayer).Marshal()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/record_layer.go:29 +0x78
  github.com/pion/dtls.(*Conn).internalSend()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:283 +0x50
  github.com/pion/dtls.serverFlightHandler()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/server_handlers.go:407 +0x98c
  github.com/pion/dtls.(*Conn).handleIncomingPacket()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:330 +0xdc1
  github.com/pion/dtls.(*Conn).handleIncoming()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:314 +0xd8
  github.com/pion/dtls.createConn.func1()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:146 +0x174
Previous write at 0x00c003731800 by goroutine 1064:
  runtime.slicecopy()
      /home/travis/.gimme/versions/go1.12.3.linux.amd64/src/runtime/slice.go:197 +0x0
  github.com/pion/dtls.prfPHash()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/prf.go:125 +0x1c6
  github.com/pion/dtls.prfVerifyData()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/prf.go:178 +0x20b
  github.com/pion/dtls.serverFlightHandler()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/prf.go:186 +0xb9d
  github.com/pion/dtls.(*Conn).startHandshakeOutbound.func1()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:434 +0x208
Goroutine 1065 (running) created at:
  github.com/pion/dtls.createConn()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:131 +0x921
  github.com/pion/webrtc/v2.(*DTLSTransport).Start()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:176 +0x815
  github.com/pion/webrtc/v2.(*PeerConnection).SetRemoteDescription.func2()
      /home/travis/gopath/pkg/mod/github.com/pion/webrtc/[email protected]/peerconnection.go:909 +0x36f
Goroutine 1064 (running) created at:
  github.com/pion/dtls.(*Conn).startHandshakeOutbound()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:422 +0x4c
  github.com/pion/dtls.createConn()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:128 +0x8fc
  github.com/pion/webrtc/v2.(*DTLSTransport).Start()
      /home/travis/gopath/pkg/mod/github.com/pion/[email protected]/conn.go:176 +0x815
  github.com/pion/webrtc/v2.(*PeerConnection).SetRemoteDescription.func2()
      /home/travis/gopath/pkg/mod/github.com/pion/webrtc/[email protected]/peerconnection.go:909 +0x36f
==================

Noteworthy about this test is that it opens multiple PeerConnections in parallel.

Deadlines are not working properly

Your environment.

What did you do?

Client side:

dtlsConn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
n, err := dtlsConn.Read(b)
if err != nil {
	panic(err) // THIS SHOULD PANIC!!
}

Server side:

<- time.After(1000 * time.Millisecond)
conn.Write([]byte("Hello world"))

Full example at: https://play.golang.org/p/aPaG4IROkFB

What did you expect?

dtlsConn.Read(b) should have returned a timeout error.

What happened?

Data was received without error exceding the deadline.

client send 2 clienthello.

Your environment.

  • Version: b4bc4798b938775e640c7d70d9c877c1096c24d0
  • Browser: chrome 71.0.3578.98
  • Other Information - use sfu-ws example

What did you do?

click the publish button

What did you expect?

There will be one client hello

What happened?

There are 2 client hello in wireshark. Maybe the timer bug.

Untitled

Panic on no supported client-requested "namedCurves"

Your environment.

  • Version: 1.5.0
  • Browser: Node.JS @nodertc/dtls library
  • Other Information:
panic: runtime error: index out of range

goroutine 266 [running]:
github.com/pion/dtls.serverHandshakeHandler.func1(0xc0000cc360, 0x52, 0x60, 0x1, 0xc0000c4050)
	/go/pkg/mod/github.com/pion/[email protected]/server_handlers.go:38 +0x13cd
github.com/pion/dtls.serverHandshakeHandler(0xc0000ec500, 0x1c9eed8, 0xc0000ec500)
	/go/pkg/mod/github.com/pion/[email protected]/server_handlers.go:163 +0x5af
github.com/pion/dtls.(*Conn).handleIncomingPacket(0xc0000ec500, 0xc000128000, 0x5f, 0x2000, 0x0, 0x0)
	/go/pkg/mod/github.com/pion/[email protected]/conn.go:417 +0x4bc
github.com/pion/dtls.(*Conn).inboundLoop(0xc0000ec500)
	/go/pkg/mod/github.com/pion/[email protected]/conn.go:360 +0x1bb
created by github.com/pion/dtls.createConn
	/go/pkg/mod/github.com/pion/[email protected]/conn.go:170 +0x600

What did you do?

  1. Started a pion/dtls listen server.
  2. Using openssl 1.0.2s client:
    openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug -cipher ECDHE-ECDSA-AES128-GCM-SHA256 -curves secp384r1

What did you expect?

Connection closes gracefully, rather than a panic

What happened?

The application panic'ed and crashed.

The offending line is here: 6dec1ec#diff-84f73d0d6a8b3cb71ba4ae9da4d57470R51

This assumes the client provides at least one supported Elliptic Curve, but in some cases the server may not support any of Elliptic Curve's that the client is requesting be used.

Support TLS_PSK_WITH_AES_128_CCM_8 for IoT usecases

Summary

I'd like to request inclusion of at least one RFC 6655 cipher suite, TLS_PSK_WITH_AES_128_CCM_8. This suite is often used for IoT products, most notably IKEA Tradfri uses it for CoAP over DTLS.

Motivation

I'd like to use a Go native DTLS library in a number of my IoT projects. Some of these projects involve talking to (or exposing as) gateways that leverage this particular cipher suite as it's fairly common in IoT products. Currently bocajim/dtls exists which implements just that cipher.

Describe alternatives you've considered

I can always use this and the other DTLS library when I happen to need more than just TLS_PSK_WITH_AES_128_CCM_8. But I would much prefer to have one maintained library with all capabilities instead of being split between multiple packages from different maintainers.

Checklist

  • Add CCM support #46
  • Add PSK support
  • Add TLS_PSK_WITH_AES_128_CCM_8

clean fmt.Println

There are codes like:
fmt.Println("handleIncoming: Handshake not finished, dropping packet")

  • use logging??
  • put these in return error message?

Data Channel connection wouldn't establish with logs from DTLS

Your environment.

  • Version: Release or SHA: 44ae5 (dtls v1.2.1, [email protected])
  • Browser: include version: n/a
  • Other Information - See below

What did you do?

Running data channel connection tests over the Internet, noticed that data channel connection wouldn't establish (never completes) close to 60% of chances (it varies depending on the location of endpoints)

What did you expect?

Data Channel connection is successfully established.

What happened?

Data channel connection establishment wouldn't complete with high occurrence ratio, ~60%. When that happens, saw following log messages would show up always.

handleIncoming: old epoch, dropping packet
handleIncoming: old epoch, dropping packet
handleIncoming: old epoch, dropping packet
handleIncoming: old epoch, dropping packet
CipherSuite has not been initialized, unable to decrypt

The above repeats forever until the application gives and closes the peer connection.

Other information:

  • This never happens on the local environment
  • We are using only one data channel for now (no media used)

RequestClientCert option can cause connection error

Your environment.

  • Version: b28063e
  • Browser: N/A
  • Other Information: OpenSSL 1.1.1c

What did you do?

Server: go run example_server.go

package main
  
import (
        "fmt"
        "net"
        "time"

        "github.com/pion/dtls"
        "github.com/pion/dtls/examples/util"
)

func main() {
    addr := &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 4444}

    certificate, privateKey, genErr := dtls.GenerateSelfSigned()
    util.Check(genErr)

    config := &dtls.Config{
        Certificate:          certificate,
        PrivateKey:           privateKey,
        ClientAuth:           dtls.RequestClientCert,
    }

    listener, err := dtls.Listen("udp", addr, config)
    util.Check(err)
    defer func() {
        util.Check(listener.Close())
    }()

    fmt.Println("Listening")

    _, err := listener.Accept()
    util.Check(err)
}

Client: openssl s_client -dtls1_2 -connect 127.0.0.1:4444 -debug

What did you expect?

The connection to succeed without error

What happened?

Listening
panic: dtls: buffer is too small

Implement Null Cipher

Summary

Add ability to use null cipher

Motivation

Reduce CPU usage

  • write the codes
  • write wiki

Implement strict version checking

We should check the version of the remote we are communicating with (and throw an error) right now we depend on the other side blowing up if they are v1.0

Race in TestSimpleReadWrite

=== RUN   TestSimpleReadWrite
==================
WARNING: DATA RACE
Write at 0x00c000216380 by goroutine 8:
  github.com/pion/dtls.testClient()
      /home/travis/gopath/src/github.com/pion/dtls/conn_test.go:115 +0x58
  github.com/pion/dtls.TestSimpleReadWrite()
      /home/travis/gopath/src/github.com/pion/dtls/bench_test.go:39 +0x313
  testing.tRunner()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:865 +0x163
Previous read at 0x00c000216380 by goroutine 9:
  github.com/pion/dtls.createConn()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:141 +0x930
  github.com/pion/dtls.Server()
      /home/travis/gopath/src/github.com/pion/dtls/conn.go:236 +0x14c
  github.com/pion/dtls.testServer()
      /home/travis/gopath/src/github.com/pion/dtls/conn_test.go:128 +0x65
  github.com/pion/dtls.TestSimpleReadWrite.func1()
      /home/travis/gopath/src/github.com/pion/dtls/bench_test.go:27 +0x72
Goroutine 8 (running) created at:
  testing.(*T).Run()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:916 +0x65a
  testing.runTests.func1()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:1157 +0xa8
  testing.tRunner()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:865 +0x163
  testing.runTests()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:1155 +0x523
  testing.(*M).Run()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:1072 +0x2eb
  main.main()
      _testmain.go:314 +0x344
Goroutine 9 (running) created at:
  github.com/pion/dtls.TestSimpleReadWrite()
      /home/travis/gopath/src/github.com/pion/dtls/bench_test.go:26 +0x2e6
  testing.tRunner()
      /home/travis/.gimme/versions/go1.12.9.linux.amd64/src/testing/testing.go:865 +0x163
==================

Release 1.4.0

There's been a number of changes since the current 1.3.x series that I believe warrant a release and a bump to the minor version.

  • AES-CCM #46
  • PSK support #66
    • TLS_PSK_WITH_AES_128_CCM_8 #76
    • TLS_PSK_WITH_AES_128_GCM_SHA256 #78

I'd also like to get #79 in.

Anything else of note or importance to get done for 1.4?

Investigate Heartbeat

Can we guard against badly behaving peers (E.g.: Not sending close_notify) using a Heartbeat? Maybe something like RFC6520?

DTLS with PSK stuck at handshake progress

Once send packet over DTLS with wrong PSK, the DTLS server will be stuck at handshaking and cannot handle other request anymore event use right PSK.

CipherSuites: TLS_PSK_WITH_AES_128_CCM_8

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.