Skip to content

Latest commit

 

History

History
69 lines (59 loc) · 3.47 KB

CONTRIBUTORS_GUIDE.md

File metadata and controls

69 lines (59 loc) · 3.47 KB

How this package works

There are numerous handshake-related structs in crypto/tls, most of which are either private or have private fields. One of them — clientHandshakeState — has private function handshake(), which is called in the beginning of default handshake.
Unfortunately, user will not be able to directly access this struct outside of tls package. As a result, we decided to employ following workaround: declare public copies of private structs. Now user is free to manipulate fields of public ClientHandshakeState. Then, right before handshake, we can shallow-copy public state into private clientHandshakeState, call handshake() on it and carry on with default Golang handshake process. After handshake is done we shallow-copy private state back to public, allowing user to read results of handshake.

Chapter 2: TLSExtension

The way we achieve reasonable flexibilty with extensions is inspired by ztls' design. However, our design has several differences, so we wrote it from scratch. This design allows us to have an array of TLSExtension objects and then marshal them in order:

type TLSExtension interface {
	writeToUConn(*UConn) error

	Len() int // includes header

	// Read reads up to len(p) bytes into p.
	// It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
	Read(p []byte) (n int, err error) // implements io.Reader
}

writeToUConn() applies appropriate per-extension changes to UConn.

Len() provides the size of marshaled extension, so we can allocate appropriate buffer beforehand, catch out-of-bound errors easily and guide size-dependent extensions such as padding.

Read(buffer []byte) writes(see: io.Reader interface) marshaled extensions into provided buffer. This avoids extra allocations.

Chapter 3: UConn

UConn extends standard tls.Conn. Most notably, it stores slice with TLSExtensions and public ClientHandshakeState.
Whenever UConn.BuildHandshakeState() gets called (happens automatically in UConn.Handshake() or could be called manually), config will be applied according to chosen ClientHelloID. From contributor's view there are 2 main behaviors:

  • HelloGolang simply calls default Golang's makeClientHello() and directly stores it into HandshakeState.Hello. utls-specific stuff is ignored.
  • Other ClientHelloIDs fill UConn.Hello.{Random, CipherSuites, CompressionMethods} and UConn.Extensions with per-parrot setup, which then gets applied to appropriate standard tls structs, and then marshaled by utls into HandshakeState.Hello.

Chapter 4: Tests

Tests exist, but coverage is very limited. What's covered is a conjunction of

  • TLS 1.2
  • Working parrots without any unsupported extensions (only Android 5.1 at this time)
  • Ciphersuites offered by parrot.
  • Ciphersuites supported by Golang
  • Simple conversation with reference implementation of OpenSSL. (e.g. no automatic checks for renegotiations, parroting quality and such)

plus we test some other minor things. Basically, current tests aim to provide a sanity check.

Merging upstream

git remote add -f golang git@github.com:golang/go.git
git checkout -b golang-upstream golang/master
git subtree split -P src/crypto/tls/ -b golang-tls-upstream
git checkout master
git merge --no-commit golang-tls-upstream