mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-01 19:17:36 +03:00
commit
736a2caf18
31 changed files with 4004 additions and 4 deletions
60
CONTRIBUTORS_GUIDE.md
Normal file
60
CONTRIBUTORS_GUIDE.md
Normal file
|
@ -0,0 +1,60 @@
|
|||
# How this package works
|
||||
### Chapter 1: [Making private things public](./u_public.go)
|
||||
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](./u_tls_extensions.go)
|
||||
The way we achieve reasonable flexibilty with extensions is inspired by
|
||||
[ztls'](https://github.com/zmap/zcrypto/blob/master/tls/handshake_extensions.go) 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:
|
||||
```Golang
|
||||
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](./u_conn.go)
|
||||
`UConn` extends standard `tls.Conn`. Most notably, it stores slice with `TLSExtension`s 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()`](./handshake_client.go)
|
||||
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.
|
141
README.md
Normal file
141
README.md
Normal file
|
@ -0,0 +1,141 @@
|
|||
# uTLS
|
||||
|
||||
## Low-level access to handshake
|
||||
* Read/write access to all bits of client hello message.
|
||||
* Read access to fields of ClientHandshakeState, which, among other things, includes ServerHello and MasterSecret.
|
||||
## ClientHello fingerprinting resistance
|
||||
Golang's ClientHello has a very unique fingerprint, which especially sticks out on mobile clients,
|
||||
where Golang is not too popular yet.
|
||||
Some members of anti-censorship community are concerned that their tools could be trivially blocked based on
|
||||
ClientHello with relatively small collateral damage. There are multiple solutions to this issue.
|
||||
#### Randomized handshake
|
||||
This package can be used to generate randomized ClientHello.
|
||||
Provides a moving target without any compatibility or parrot-is-dead attack risks.
|
||||
**Feedback about implementation details of randomized handshake is extremely appreciated.**
|
||||
#### Parroting
|
||||
This package can be used to parrot ClientHello of popular browsers.
|
||||
There are some caveats to this parroting:
|
||||
* We are forced to offer ciphersuites and tls extensions that are not supported by crypto/tls.
|
||||
This is not a problem, if you fully control the server and turn unsupported things off on server side.
|
||||
* Parroting could be imperfect, and there is no parroting beyond ClientHello.
|
||||
##### Compatibility risks of available parrotsThis package allows ClientHello messages to parrot popular browsers. There are few caveats to this parroting:
|
||||
* We are forced to offer ciphersuites and tls extensions setups that are not supported by crypto/tls.
|
||||
This is not a problem, if you fully control the server.
|
||||
* Parroting could be imperfect, and there is no parroting beyond ClientHello.\
|
||||
|
||||
| Parrot | Ciphers* | Signature* | Unsupported extensions |
|
||||
| ------------- | -------- | ---------- | --------------------------------- |
|
||||
| Android 5.1 | low | very low | None |
|
||||
| Android 6.0 | low | very low | Extended Master Secret** |
|
||||
| Chrome 58 | no | low | Extended Master Secret**, ChannelID |
|
||||
|
||||
\* Denotes very rough guesstimate of likelihood that unsupported things will get echoed back by the server in the wild,
|
||||
visibly breaking the connection.
|
||||
\*\* New extensions such as EMS become popular quickly, so it's not recommended to use with servers you don't own.
|
||||
As seen in table, many good parrots will become available once EMS is implemented in crypto/tls.
|
||||
##### Work-in-progress parrots
|
||||
Not finished yet!
|
||||
|
||||
| Parrot | Ciphers* | Signature* | Unsupported extensions |
|
||||
| ------------- | -------- | ---------- | --------------------------------- |
|
||||
| Firefox 53 | low | low | Extended Master Secret** |
|
||||
##### Parrots FAQ
|
||||
> Does it really look like, say, Google Chrome with all the [GREASE](https://tools.ietf.org/html/draft-davidben-tls-grease-01) and stuff?
|
||||
|
||||
It LGTM, but please open up Wireshark and check. If you see something — [say something](issues).
|
||||
|
||||
> Aren't there side channels? Everybody knows that the ~~bird is a word~~[parrot is dead](https://people.cs.umass.edu/~amir/papers/parrot.pdf)
|
||||
|
||||
There sure are. If you found one that approaches practicality at line speed — [please tell us](issues).
|
||||
|
||||
##### Things to implement in Golang to make parrots better
|
||||
* Extended Master Secret and ChannelID extensions
|
||||
* Enable sha512 and sha224 hashes by default
|
||||
* Implement RSA PSS signature algorithms
|
||||
* In general, any modern crypto is likely to be useful going forward.
|
||||
#### Custom Handshake
|
||||
It is possible to create custom handshake by
|
||||
1) Use `HelloCustom` as an argument for `UClient()` to get empty config
|
||||
2) Fill tls header fields: UConn.Hello.{Random, CipherSuites, CompressionMethods}, if needed, or stick to defaults.
|
||||
3) Configure and add various [TLS Extensions](u_tls_extensions.go) to UConn.Extensions: they will be marshaled in order.
|
||||
4) Set Session and SessionCache, as needed.
|
||||
|
||||
If you need to manually control all the bytes on the wire(certainly not recommended!),
|
||||
you can set UConn.HandshakeStateBuilt = true, and marshal clientHello into UConn.HandshakeState.Hello.raw yourself.
|
||||
In this case you will be responsible for modifying other parts of Config and ClientHelloMsg to reflect your setup.
|
||||
## Fake Session Tickets
|
||||
Set of provided functions is likely to change, as use-cases aren't fully worked out yet.
|
||||
Currently, there is a simple function to set session ticket to any desired state:
|
||||
|
||||
```Golang
|
||||
func (c *ExtendedConfig) SetSessionState(session *ClientSessionState)
|
||||
```
|
||||
|
||||
Note that session tickets (fake ones or otherwise) are not reused.
|
||||
To reuse tickets, create a shared cache and set it on current and further configs:
|
||||
|
||||
```Golang
|
||||
func (c *ExtendedConfig) SetSessionCache(cache ClientSessionCache)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Find other examples [here](examples/examples.go).
|
||||
|
||||
For a reference, here's how default "crypto/tls" is used:
|
||||
```Golang
|
||||
config := tls.Config{ServerName: "www.google.com"}
|
||||
dialConn, err := net.Dial("tcp", "172.217.11.46:443")
|
||||
if err != nil {
|
||||
fmt.Printf("net.Dial() failed: %+v\n", err)
|
||||
return
|
||||
}
|
||||
tlsConn := tls.Client(dialConn, &config)
|
||||
err = tlsConn.Handshake()
|
||||
if err != nil {
|
||||
fmt.Printf("tlsConn.Handshake() error: %+v", err)
|
||||
return
|
||||
}
|
||||
```
|
||||
Now, if you want to use uTLS, simply substitute `tlsConn := tls.Client(dialConn, &config)`
|
||||
with `tlsConn := utls.UClient(dialConn, &config, clientHelloID)`
|
||||
where clientHelloID is one of the following:
|
||||
|
||||
1. ```utls.HelloRandomized``` adds/reorders extensions, ciphersuites, etc. randomly.
|
||||
`HelloRandomized` adds ALPN in 50% of cases, you may want to use `HelloRandomizedALPN` or
|
||||
`HelloRandomizedNoALPN` to choose specific behavior explicitly, as ALPN might affect application layer.
|
||||
2. ```utls.HelloGolang```
|
||||
HelloGolang will use default "crypto/tls" handshake marshaling codepath, which WILL
|
||||
overwrite your changes to Hello(Config, Session are fine).
|
||||
You might want to call BuildHandshakeState() before applying any changes.
|
||||
UConn.Extensions will be completely ignored.
|
||||
3. ```utls.HelloCustom```
|
||||
will prepare ClientHello with empty uconn.Extensions so you can fill it with TLSExtension's manually.
|
||||
4. The rest will will parrot given browser.
|
||||
* `utls.HelloChrome_Auto`- parrots recommended(latest) Google Chrome version
|
||||
* `utls.HelloChrome_58` - parrots Google Chrome 58
|
||||
* `utls.HelloFirefox_Auto` - parrots recommended(latest) Firefox version
|
||||
* `utls.HelloFirefox_53_WIP` - parrots Firefox 53 (Work in progress!)
|
||||
* `utls.HelloAndroid_Auto`
|
||||
* `utls.HelloAndroid_6_0_Browser`
|
||||
* `utls.HelloAndroid_5_1_Browser`
|
||||
|
||||
##### Customizing handshake
|
||||
|
||||
Before doing `Handshake()` you can also set fake session ticket, set clientHello or change uconn in other ways:
|
||||
```Golang
|
||||
cRandom := []byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
|
||||
130, 131}
|
||||
tlsConn.SetClientRandom(cRandom)
|
||||
masterSecret := make([]byte, 48)
|
||||
copy(masterSecret, []byte("masterSecret is NOT sent over the wire")) // you may use it for real security
|
||||
|
||||
// Create a session ticket that wasn't actually issued by the server.
|
||||
sessionState := utls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12),
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
masterSecret,
|
||||
nil, nil)
|
||||
tlsConn.SetSessionState(sessionState)
|
||||
```
|
|
@ -15,7 +15,7 @@ import (
|
|||
"crypto/x509"
|
||||
"hash"
|
||||
|
||||
"golang_org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// a keyAgreement implements the client and server side of a TLS key agreement
|
||||
|
|
17
cipherhw/asm_amd64.s
Normal file
17
cipherhw/asm_amd64.s
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func hasAESNI() bool
|
||||
TEXT ·hasAESNI(SB),NOSPLIT,$0
|
||||
XORQ AX, AX
|
||||
INCL AX
|
||||
CPUID
|
||||
SHRQ $25, CX
|
||||
ANDQ $1, CX
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
44
cipherhw/asm_s390x.s
Normal file
44
cipherhw/asm_s390x.s
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build s390x,!gccgo,!appengine
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func hasHWSupport() bool
|
||||
TEXT ·hasHWSupport(SB),NOSPLIT,$16-1
|
||||
XOR R0, R0 // set function code to 0 (query)
|
||||
LA mask-16(SP), R1 // 16-byte stack variable for mask
|
||||
MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
|
||||
|
||||
// check for KM AES functions
|
||||
WORD $0xB92E0024 // cipher message (KM)
|
||||
MOVD mask-16(SP), R2
|
||||
AND R3, R2
|
||||
CMPBNE R2, R3, notfound
|
||||
|
||||
// check for KMC AES functions
|
||||
WORD $0xB92F0024 // cipher message with chaining (KMC)
|
||||
MOVD mask-16(SP), R2
|
||||
AND R3, R2
|
||||
CMPBNE R2, R3, notfound
|
||||
|
||||
// check for KMCTR AES functions
|
||||
WORD $0xB92D4024 // cipher message with counter (KMCTR)
|
||||
MOVD mask-16(SP), R2
|
||||
AND R3, R2
|
||||
CMPBNE R2, R3, notfound
|
||||
|
||||
// check for KIMD GHASH function
|
||||
WORD $0xB93E0024 // compute intermediate message digest (KIMD)
|
||||
MOVD mask-8(SP), R2 // bits 64-127
|
||||
MOVD $(1<<62), R5
|
||||
AND R5, R2
|
||||
CMPBNE R2, R5, notfound
|
||||
|
||||
MOVB $1, ret+0(FP)
|
||||
RET
|
||||
notfound:
|
||||
MOVB $0, ret+0(FP)
|
||||
RET
|
16
cipherhw/cipherhw_amd64.go
Normal file
16
cipherhw/cipherhw_amd64.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
package cipherhw
|
||||
|
||||
// defined in asm_amd64.s
|
||||
func hasAESNI() bool
|
||||
|
||||
// AESGCMSupport returns true if the Go standard library supports AES-GCM in
|
||||
// hardware.
|
||||
func AESGCMSupport() bool {
|
||||
return hasAESNI()
|
||||
}
|
18
cipherhw/cipherhw_s390x.go
Normal file
18
cipherhw/cipherhw_s390x.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build s390x,!gccgo,!appengine
|
||||
|
||||
package cipherhw
|
||||
|
||||
// hasHWSupport reports whether the AES-128, AES-192 and AES-256 cipher message
|
||||
// (KM) function codes are supported. Note that this function is expensive.
|
||||
// defined in asm_s390x.s
|
||||
func hasHWSupport() bool
|
||||
|
||||
var hwSupport = hasHWSupport()
|
||||
|
||||
func AESGCMSupport() bool {
|
||||
return hwSupport
|
||||
}
|
7
cipherhw/doc.go
Normal file
7
cipherhw/doc.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cipherhw exposes common functions for detecting whether hardware
|
||||
// support for certain ciphers and authenticators is present.
|
||||
package cipherhw
|
11
cipherhw/generic.go
Normal file
11
cipherhw/generic.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !amd64,!s390x gccgo appengine
|
||||
|
||||
package cipherhw
|
||||
|
||||
func AESGCMSupport() bool {
|
||||
return false
|
||||
}
|
|
@ -7,12 +7,12 @@ package tls
|
|||
import (
|
||||
"container/list"
|
||||
"crypto"
|
||||
"crypto/internal/cipherhw"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Jigsaw-Code/utls/cipherhw"
|
||||
"io"
|
||||
"math/big"
|
||||
"net"
|
||||
|
|
224
examples/examples.go
Normal file
224
examples/examples.go
Normal file
|
@ -0,0 +1,224 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
tls "github.com/Jigsaw-Code/utls"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
dialTimeout = time.Duration(15) * time.Second
|
||||
sessionTicket = []uint8(`Here goes phony session ticket: phony enough to get into ASCII range
|
||||
Ticket could be of any length, but for camouflage purposes it's better to use uniformly random contents
|
||||
and standard length such as 228`)
|
||||
)
|
||||
|
||||
func HttpGetDefault(hostname string, addr string) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
tlsConn := tls.Client(dialConn, &config)
|
||||
defer tlsConn.Close()
|
||||
|
||||
err = tlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("tlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
tlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
tlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func HttpGetByHelloID(hostname string, addr string, helloID tls.ClientHelloID) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, &config, helloID)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func HttpGetExplicitRandom(hostname string, addr string) (string, error) {
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, nil, tls.HelloGolang)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
uTlsConn.SetSNI(hostname) // have to set SNI, if config was nil
|
||||
err = uTlsConn.BuildHandshakeState()
|
||||
if err != nil {
|
||||
// have to call BuildHandshakeState() first, when using default UClient, to avoid settings' overwriting
|
||||
return "", fmt.Errorf("uTlsConn.BuildHandshakeState() error: %+v", err)
|
||||
}
|
||||
|
||||
cRandom := []byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
|
||||
130, 131}
|
||||
uTlsConn.SetClientRandom(cRandom)
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
// These fields are accessible regardless of setting client hello explicitly
|
||||
fmt.Printf("#> MasterSecret:\n%s", hex.Dump(uTlsConn.HandshakeState.MasterSecret))
|
||||
fmt.Printf("#> ClientHello Random:\n%s", hex.Dump(uTlsConn.HandshakeState.Hello.Random))
|
||||
fmt.Printf("#> ServerHello Random:\n%s", hex.Dump(uTlsConn.HandshakeState.ServerHello.Random))
|
||||
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// Note that the server will reject the fake ticket(unless you set up your server to accept them) and do full handshake
|
||||
func HttpGetTicket(hostname string, addr string) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, &config, tls.HelloGolang)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
err = uTlsConn.BuildHandshakeState()
|
||||
if err != nil {
|
||||
// have to call BuildHandshakeState() first, when using default UClient, to avoid settings' overwriting
|
||||
return "", fmt.Errorf("uTlsConn.BuildHandshakeState() error: %+v", err)
|
||||
}
|
||||
|
||||
masterSecret := make([]byte, 48)
|
||||
copy(masterSecret, []byte("masterSecret is NOT sent over the wire")) // you may use it for real security
|
||||
|
||||
// Create a session ticket that wasn't actually issued by the server.
|
||||
sessionState := tls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12),
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
masterSecret,
|
||||
nil, nil)
|
||||
|
||||
uTlsConn.SetSessionState(sessionState)
|
||||
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
fmt.Println("#> This is how client hello with session ticket looked:")
|
||||
fmt.Print(hex.Dump(uTlsConn.HandshakeState.Hello.Raw))
|
||||
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// Note that the server will reject the fake ticket(unless you set up your server to accept them) and do full handshake
|
||||
func HttpGetTicketHelloID(hostname string, addr string, helloID tls.ClientHelloID) (string, error) {
|
||||
config := tls.Config{ServerName: hostname}
|
||||
dialConn, err := net.DialTimeout("tcp", addr, dialTimeout)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("net.DialTimeout error: %+v", err)
|
||||
}
|
||||
uTlsConn := tls.UClient(dialConn, &config, helloID)
|
||||
defer uTlsConn.Close()
|
||||
|
||||
masterSecret := make([]byte, 48)
|
||||
copy(masterSecret, []byte("masterSecret is NOT sent over the wire")) // you may use it for real security
|
||||
|
||||
// Create a session ticket that wasn't actually issued by the server.
|
||||
sessionState := tls.MakeClientSessionState(sessionTicket, uint16(tls.VersionTLS12),
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
masterSecret,
|
||||
nil, nil)
|
||||
|
||||
uTlsConn.SetSessionState(sessionState)
|
||||
err = uTlsConn.Handshake()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
|
||||
}
|
||||
|
||||
fmt.Println("#> This is how client hello with session ticket looked:")
|
||||
fmt.Print(hex.Dump(uTlsConn.HandshakeState.Hello.Raw))
|
||||
|
||||
uTlsConn.Write([]byte("GET / HTTP/1.1\r\nHost: " + hostname + "\r\n\r\n"))
|
||||
buf := make([]byte, 14096)
|
||||
uTlsConn.Read(buf)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var response string
|
||||
var err error
|
||||
requestHostname := "www.google.com"
|
||||
requestAddr := "172.217.11.46:443"
|
||||
|
||||
response, err = HttpGetDefault(requestHostname, requestAddr)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetDefault failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetDefault response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetByHelloID(requestHostname, requestAddr, tls.HelloAndroid_5_1_Browser)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetByHelloID(Android_5_1) failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetByHelloID(Android_5_1) response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetByHelloID(requestHostname, requestAddr, tls.HelloRandomizedNoALPN)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetByHelloID(Randomized) failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetByHelloID(Randomized) response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetExplicitRandom(requestHostname, requestAddr)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetExplicitRandom failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetExplicitRandom response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetTicket(requestHostname, requestAddr)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetTicket failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetTicket response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
response, err = HttpGetTicketHelloID(requestHostname, requestAddr, tls.HelloAndroid_5_1_Browser)
|
||||
if err != nil {
|
||||
fmt.Printf("#> HttpGetTicketHelloID(Android_5_1) failed: %+v\n", err)
|
||||
} else {
|
||||
fmt.Printf("#> HttpGetTicketHelloID(Android_5_1) response: %+s\n", getFirstLine(response))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getFirstLine(s string) string {
|
||||
ss := strings.Split(s, "\r\n")
|
||||
if len(ss) == 0 {
|
||||
return ""
|
||||
} else {
|
||||
return ss[0]
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ import (
|
|||
"io"
|
||||
"math/big"
|
||||
|
||||
"golang_org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
|
||||
|
|
2
prf.go
2
prf.go
|
@ -189,6 +189,8 @@ func lookupTLSHash(hash uint8) (crypto.Hash, error) {
|
|||
return crypto.SHA256, nil
|
||||
case hashSHA384:
|
||||
return crypto.SHA384, nil
|
||||
case disabledHashSHA512:
|
||||
return crypto.SHA512, nil
|
||||
default:
|
||||
return 0, errors.New("tls: unsupported hash algorithm")
|
||||
}
|
||||
|
|
93
testdata/Client-TLSv12-UTLS-AES128-GCM-SHA256-Android-22
vendored
Normal file
93
testdata/Client-TLSv12-UTLS-AES128-GCM-SHA256-Android-22
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 c0 01 00 00 bc 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2a cc 14 |.............*..|
|
||||
00000030 cc 13 cc 15 c0 2f c0 2b 00 9e c0 14 c0 0a 00 39 |...../.+.......9|
|
||||
00000040 c0 13 c0 09 00 33 c0 11 c0 07 00 9c 00 35 00 2f |.....3.......5./|
|
||||
00000050 00 05 00 04 00 0a 00 ff 01 00 00 69 00 00 00 05 |...........i....|
|
||||
00000060 00 03 00 00 00 00 23 00 00 00 0d 00 16 00 14 06 |......#.........|
|
||||
00000070 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 |................|
|
||||
00000080 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 |............3t..|
|
||||
00000090 00 12 00 00 00 10 00 1b 00 19 08 68 74 74 70 2f |...........http/|
|
||||
000000a0 31 2e 31 06 73 70 64 79 2f 33 08 73 70 64 79 2f |1.1.spdy/3.spdy/|
|
||||
000000b0 33 2e 31 00 0b 00 02 01 00 00 0a 00 08 00 06 00 |3.1.............|
|
||||
000000c0 17 00 18 00 19 |.....|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 35 02 00 00 31 03 03 cb 9e 94 a0 b8 |....5...1.......|
|
||||
00000010 29 60 4d d5 b3 20 b5 12 b3 9c 5c 50 7b 2e e0 93 |)`M.. ....\P{...|
|
||||
00000020 7b d2 ad 74 89 b8 fe 8a 05 93 da 00 00 9c 00 00 |{..t............|
|
||||
00000030 09 ff 01 00 01 00 00 23 00 00 16 03 03 02 59 0b |.......#......Y.|
|
||||
00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
|
||||
00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
|
||||
00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
|
||||
00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
|
||||
00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
|
||||
00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
|
||||
000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
|
||||
000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
|
||||
000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
|
||||
000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
|
||||
000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
|
||||
000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
|
||||
00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
|
||||
00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
|
||||
00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
|
||||
00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
|
||||
00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
|
||||
00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
|
||||
00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
|
||||
00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
|
||||
00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
|
||||
00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
|
||||
000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
|
||||
000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
|
||||
000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
|
||||
000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
|
||||
000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
|
||||
000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
|
||||
00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
|
||||
00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
|
||||
00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
|
||||
00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
|
||||
00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
|
||||
00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
|
||||
00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
|
||||
00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
|
||||
00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
|
||||
00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
|
||||
000002a0 00 |.|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
|
||||
00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
|
||||
00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
|
||||
00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
|
||||
00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
|
||||
00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
|
||||
00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
|
||||
00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
|
||||
00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
|
||||
00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 52 db |.....(........R.|
|
||||
000000a0 dc 3d 1d a6 b3 40 aa ca 3c 0a 4c 1f 97 2b 55 c9 |.=...@..<.L..+U.|
|
||||
000000b0 ed e6 3d c6 18 7a 6a 72 53 59 93 4d c2 6e |..=..zjrSY.M.n|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 aa 04 00 00 a6 00 00 1c 20 00 a0 ac |............ ...|
|
||||
00000010 ff 5e 61 8a 55 04 80 bf 96 3a c2 70 9a cd 40 c3 |.^a.U....:.p..@.|
|
||||
00000020 7b bb 9d 30 15 d9 bd 23 60 6a 6f 30 8b 2d 88 22 |{..0...#`jo0.-."|
|
||||
00000030 0f cc 24 ee a5 a5 ea 0d a4 62 60 ff f0 42 42 59 |..$......b`..BBY|
|
||||
00000040 a0 b3 56 af 67 20 60 cd 54 c3 09 05 dc 13 91 1b |..V.g `.T.......|
|
||||
00000050 c8 14 51 7d 7d b2 f3 f0 fe 5d 95 cb 9e 70 62 cb |..Q}}....]...pb.|
|
||||
00000060 23 8d 7d ab 17 77 96 05 9f e5 0a f2 11 cb 95 27 |#.}..w.........'|
|
||||
00000070 01 dd 25 ab 56 ce df 6a 2f f5 22 44 59 3a 29 b1 |..%.V..j/."DY:).|
|
||||
00000080 bf 55 e9 11 76 d0 92 9a 96 ec 60 f8 08 18 8f 0e |.U..v.....`.....|
|
||||
00000090 66 fc e7 65 e9 91 e8 e9 f1 8d 66 5f b9 73 cc d8 |f..e......f_.s..|
|
||||
000000a0 ab 8b e0 e3 77 74 53 69 9d 4d f6 f5 a2 54 2c 14 |....wtSi.M...T,.|
|
||||
000000b0 03 03 00 01 01 16 03 03 00 28 fc 68 19 6d c3 b8 |.........(.h.m..|
|
||||
000000c0 fb 43 f8 53 d0 be f2 56 52 0a 94 ca 30 6a ee 2a |.C.S...VR...0j.*|
|
||||
000000d0 05 a3 bd c5 d1 f7 9c 47 6f 59 12 15 0d 9c 60 b2 |.......GoY....`.|
|
||||
000000e0 7d 6e |}n|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 4c 8c 50 |.............L.P|
|
||||
00000010 c0 ff dd a5 5f 99 50 46 a4 92 88 d9 15 27 4e b3 |...._.PF.....'N.|
|
||||
00000020 74 bf 94 15 03 03 00 1a 00 00 00 00 00 00 00 02 |t...............|
|
||||
00000030 c7 15 f6 3d 97 e6 2c de 60 69 4e 3e ed ca e7 cc |...=..,.`iN>....|
|
||||
00000040 09 8f |..|
|
98
testdata/Client-TLSv12-UTLS-ECDHE-ECDSA-AES128-GCM-SHA256-Android-22
vendored
Normal file
98
testdata/Client-TLSv12-UTLS-ECDHE-ECDSA-AES128-GCM-SHA256-Android-22
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 c0 01 00 00 bc 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2a cc 14 |.............*..|
|
||||
00000030 cc 13 cc 15 c0 2f c0 2b 00 9e c0 14 c0 0a 00 39 |...../.+.......9|
|
||||
00000040 c0 13 c0 09 00 33 c0 11 c0 07 00 9c 00 35 00 2f |.....3.......5./|
|
||||
00000050 00 05 00 04 00 0a 00 ff 01 00 00 69 00 00 00 05 |...........i....|
|
||||
00000060 00 03 00 00 00 00 23 00 00 00 0d 00 16 00 14 06 |......#.........|
|
||||
00000070 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 |................|
|
||||
00000080 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 |............3t..|
|
||||
00000090 00 12 00 00 00 10 00 1b 00 19 08 68 74 74 70 2f |...........http/|
|
||||
000000a0 31 2e 31 06 73 70 64 79 2f 33 08 73 70 64 79 2f |1.1.spdy/3.spdy/|
|
||||
000000b0 33 2e 31 00 0b 00 02 01 00 00 0a 00 08 00 06 00 |3.1.............|
|
||||
000000c0 17 00 18 00 19 |.....|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 3d 02 00 00 39 03 03 74 61 47 f3 35 |....=...9..taG.5|
|
||||
00000010 bb c9 02 ae 3f 28 de bb 86 56 7c ce 01 37 bc 6b |....?(...V|..7.k|
|
||||
00000020 37 bf 72 46 6b 21 c8 6c 47 c6 04 00 c0 2b 00 00 |7.rFk!.lG....+..|
|
||||
00000030 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 23 |...............#|
|
||||
00000040 00 00 16 03 03 02 0e 0b 00 02 0a 00 02 07 00 02 |................|
|
||||
00000050 04 30 82 02 00 30 82 01 62 02 09 00 b8 bf 2d 47 |.0...0..b.....-G|
|
||||
00000060 a0 d2 eb f4 30 09 06 07 2a 86 48 ce 3d 04 01 30 |....0...*.H.=..0|
|
||||
00000070 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 |E1.0...U....AU1.|
|
||||
00000080 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 |0...U....Some-St|
|
||||
00000090 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e |ate1!0...U....In|
|
||||
000000a0 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 |ternet Widgits P|
|
||||
000000b0 74 79 20 4c 74 64 30 1e 17 0d 31 32 31 31 32 32 |ty Ltd0...121122|
|
||||
000000c0 31 35 30 36 33 32 5a 17 0d 32 32 31 31 32 30 31 |150632Z..2211201|
|
||||
000000d0 35 30 36 33 32 5a 30 45 31 0b 30 09 06 03 55 04 |50632Z0E1.0...U.|
|
||||
000000e0 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
|
||||
000000f0 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
|
||||
00000100 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
|
||||
00000110 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 9b |dgits Pty Ltd0..|
|
||||
00000120 30 10 06 07 2a 86 48 ce 3d 02 01 06 05 2b 81 04 |0...*.H.=....+..|
|
||||
00000130 00 23 03 81 86 00 04 00 c4 a1 ed be 98 f9 0b 48 |.#.............H|
|
||||
00000140 73 36 7e c3 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d |s6~..V.".=S.;M!=|
|
||||
00000150 cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 |.ku......&.....r|
|
||||
00000160 32 7c b3 64 2f 1c 90 bc ea 68 23 10 7e fe e3 25 |2|.d/....h#.~..%|
|
||||
00000170 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 |.H:i.(m.7...b...|
|
||||
00000180 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 |.pb....d1...1...|
|
||||
00000190 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 |h..#.vd?.\....XX|
|
||||
000001a0 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 |._p............0|
|
||||
000001b0 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 09 06 07 2a |f[f. .'...;0...*|
|
||||
000001c0 86 48 ce 3d 04 01 03 81 8c 00 30 81 88 02 42 01 |.H.=......0...B.|
|
||||
000001d0 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 ed 98 9d ae |..O..E.H}.......|
|
||||
000001e0 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 |Gp.^../...M.a@..|
|
||||
000001f0 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce |....~.~.v..;~.?.|
|
||||
00000200 fa 10 e2 59 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f |...Y.G-|..N....o|
|
||||
00000210 d0 02 42 01 4d fc be 67 13 9c 2d 05 0e bd 3f a3 |..B.M..g..-...?.|
|
||||
00000220 8c 25 c1 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a |.%.3.......7z..z|
|
||||
00000230 c9 86 2e dd d7 11 69 7f 85 7c 56 de fb 31 78 2b |......i..|V..1x+|
|
||||
00000240 e4 c7 78 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 |..x.....N6$1{j.9|
|
||||
00000250 95 12 07 8f 2a 16 03 03 00 d7 0c 00 00 d3 03 00 |....*...........|
|
||||
00000260 17 41 04 32 22 ad 08 03 13 30 89 c0 79 a9 cd 4e |.A.2"....0..y..N|
|
||||
00000270 b1 6b 6c 20 c1 80 04 2a d2 4f 74 52 b2 4d 21 71 |.kl ...*.OtR.M!q|
|
||||
00000280 82 5d 31 5a 72 f4 7c 78 da d7 2d e8 55 9a 87 6d |.]1Zr.|x..-.U..m|
|
||||
00000290 43 e7 13 f1 0e 00 25 e9 e4 ac 45 cd 82 7e 84 28 |C.....%...E..~.(|
|
||||
000002a0 e2 b4 84 06 03 00 8a 30 81 87 02 42 00 dd 86 fa |.......0...B....|
|
||||
000002b0 7a a6 8c b3 c6 73 f7 b5 f8 ba a7 16 6d d9 09 ea |z....s......m...|
|
||||
000002c0 cd dd 82 83 44 0c 3f b1 0f 23 a3 61 76 eb eb 5a |....D.?..#.av..Z|
|
||||
000002d0 88 d5 65 31 3f ba 81 84 0c 35 17 4f 2f 02 fb 8d |..e1?....5.O/...|
|
||||
000002e0 21 1b c1 de 42 40 d8 a9 84 4a 44 f1 0c 3c 02 41 |!...B@...JD..<.A|
|
||||
000002f0 76 8e 43 e9 c4 f7 47 68 03 23 6d 36 8e 9d 30 9a |v.C...Gh.#m6..0.|
|
||||
00000300 71 6d a5 76 c0 20 d8 0e bd f6 dd 11 34 a8 e7 af |qm.v. ......4...|
|
||||
00000310 85 a7 01 19 68 c8 df fa 9c 62 e1 71 b2 9b 01 83 |....h....b.q....|
|
||||
00000320 8e 9b 96 e2 6d 30 71 ff 3b c4 70 16 a3 f8 59 2e |....m0q.;.p...Y.|
|
||||
00000330 b8 16 03 03 00 04 0e 00 00 00 |..........|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
|
||||
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
|
||||
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
|
||||
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
|
||||
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
|
||||
00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 de cf |.....(..........|
|
||||
00000060 13 d9 c7 68 45 02 da b9 8f fc fa 22 cf f1 2c 28 |...hE......"..,(|
|
||||
00000070 ad f4 41 aa ae be 48 dd 44 51 a7 84 46 2e |..A...H.DQ..F.|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 aa 04 00 00 a6 00 00 1c 20 00 a0 74 |............ ..t|
|
||||
00000010 80 d3 58 e2 3d dc 88 e2 73 88 cf 27 03 c5 a9 b8 |..X.=...s..'....|
|
||||
00000020 52 09 cc c7 07 9f c5 8e a4 35 d5 fe 52 71 29 00 |R........5..Rq).|
|
||||
00000030 90 a7 b8 49 1f 17 0b e6 1c b1 4c 05 3a d1 bd 7b |...I......L.:..{|
|
||||
00000040 c1 1e 24 6e 5f 2e 57 c3 8f 40 a4 a4 e9 05 cb 89 |..$n_.W..@......|
|
||||
00000050 1a 27 88 ee 20 7e 0f 3c 36 cc bb 1a 9a 5b 57 41 |.'.. ~.<6....[WA|
|
||||
00000060 c5 a5 c8 ac b8 7b dc 38 04 38 8e 81 7a fd ad e8 |.....{.8.8..z...|
|
||||
00000070 d4 17 29 70 92 bc 8d 95 1d 8d 11 85 75 e6 1b 4a |..)p........u..J|
|
||||
00000080 73 b7 75 da ac 63 59 ea 50 e9 ad 18 4f 2f f6 b3 |s.u..cY.P...O/..|
|
||||
00000090 c3 d7 46 5f f3 c3 de 08 b9 e8 b2 f9 99 33 ef 3d |..F_.........3.=|
|
||||
000000a0 87 10 5d f0 26 22 4f 34 10 d1 b5 5c eb 46 44 14 |..].&"O4...\.FD.|
|
||||
000000b0 03 03 00 01 01 16 03 03 00 28 d5 de 79 dc a4 08 |.........(..y...|
|
||||
000000c0 ef 79 7f 0b e8 dd 11 71 5b 13 9a de 97 d4 35 59 |.y.....q[.....5Y|
|
||||
000000d0 a0 eb f4 9e 6f 01 a2 4f cc 59 ea 57 dc 56 44 09 |....o..O.Y.W.VD.|
|
||||
000000e0 2a 92 |*.|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 c6 26 13 |..............&.|
|
||||
00000010 84 33 41 b2 e6 ab cf d8 b7 bd 7d a2 72 69 05 0d |.3A.......}.ri..|
|
||||
00000020 8f a3 4c 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..L.............|
|
||||
00000030 41 d1 25 7e 36 4d 9c 53 38 a6 16 45 67 c5 66 4d |A.%~6M.S8..Eg.fM|
|
||||
00000040 ff b0 |..|
|
103
testdata/Client-TLSv12-UTLS-ECDHE-ECDSA-AES128-SHA-Android-22
vendored
Normal file
103
testdata/Client-TLSv12-UTLS-ECDHE-ECDSA-AES128-SHA-Android-22
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 c0 01 00 00 bc 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2a cc 14 |.............*..|
|
||||
00000030 cc 13 cc 15 c0 2f c0 2b 00 9e c0 14 c0 0a 00 39 |...../.+.......9|
|
||||
00000040 c0 13 c0 09 00 33 c0 11 c0 07 00 9c 00 35 00 2f |.....3.......5./|
|
||||
00000050 00 05 00 04 00 0a 00 ff 01 00 00 69 00 00 00 05 |...........i....|
|
||||
00000060 00 03 00 00 00 00 23 00 00 00 0d 00 16 00 14 06 |......#.........|
|
||||
00000070 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 |................|
|
||||
00000080 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 |............3t..|
|
||||
00000090 00 12 00 00 00 10 00 1b 00 19 08 68 74 74 70 2f |...........http/|
|
||||
000000a0 31 2e 31 06 73 70 64 79 2f 33 08 73 70 64 79 2f |1.1.spdy/3.spdy/|
|
||||
000000b0 33 2e 31 00 0b 00 02 01 00 00 0a 00 08 00 06 00 |3.1.............|
|
||||
000000c0 17 00 18 00 19 |.....|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 3d 02 00 00 39 03 03 05 b2 2d 0b 47 |....=...9....-.G|
|
||||
00000010 a6 e2 54 d4 e1 9b 7a 41 4f ea 60 5a 1f fd fe 38 |..T...zAO.`Z...8|
|
||||
00000020 42 3f a3 26 f5 6c 6e 09 eb ee 04 00 c0 09 00 00 |B?.&.ln.........|
|
||||
00000030 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 23 |...............#|
|
||||
00000040 00 00 16 03 03 02 0e 0b 00 02 0a 00 02 07 00 02 |................|
|
||||
00000050 04 30 82 02 00 30 82 01 62 02 09 00 b8 bf 2d 47 |.0...0..b.....-G|
|
||||
00000060 a0 d2 eb f4 30 09 06 07 2a 86 48 ce 3d 04 01 30 |....0...*.H.=..0|
|
||||
00000070 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 |E1.0...U....AU1.|
|
||||
00000080 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 |0...U....Some-St|
|
||||
00000090 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e |ate1!0...U....In|
|
||||
000000a0 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 |ternet Widgits P|
|
||||
000000b0 74 79 20 4c 74 64 30 1e 17 0d 31 32 31 31 32 32 |ty Ltd0...121122|
|
||||
000000c0 31 35 30 36 33 32 5a 17 0d 32 32 31 31 32 30 31 |150632Z..2211201|
|
||||
000000d0 35 30 36 33 32 5a 30 45 31 0b 30 09 06 03 55 04 |50632Z0E1.0...U.|
|
||||
000000e0 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
|
||||
000000f0 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
|
||||
00000100 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
|
||||
00000110 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 9b |dgits Pty Ltd0..|
|
||||
00000120 30 10 06 07 2a 86 48 ce 3d 02 01 06 05 2b 81 04 |0...*.H.=....+..|
|
||||
00000130 00 23 03 81 86 00 04 00 c4 a1 ed be 98 f9 0b 48 |.#.............H|
|
||||
00000140 73 36 7e c3 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d |s6~..V.".=S.;M!=|
|
||||
00000150 cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 |.ku......&.....r|
|
||||
00000160 32 7c b3 64 2f 1c 90 bc ea 68 23 10 7e fe e3 25 |2|.d/....h#.~..%|
|
||||
00000170 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 |.H:i.(m.7...b...|
|
||||
00000180 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 |.pb....d1...1...|
|
||||
00000190 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 |h..#.vd?.\....XX|
|
||||
000001a0 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 |._p............0|
|
||||
000001b0 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 09 06 07 2a |f[f. .'...;0...*|
|
||||
000001c0 86 48 ce 3d 04 01 03 81 8c 00 30 81 88 02 42 01 |.H.=......0...B.|
|
||||
000001d0 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 ed 98 9d ae |..O..E.H}.......|
|
||||
000001e0 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 |Gp.^../...M.a@..|
|
||||
000001f0 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce |....~.~.v..;~.?.|
|
||||
00000200 fa 10 e2 59 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f |...Y.G-|..N....o|
|
||||
00000210 d0 02 42 01 4d fc be 67 13 9c 2d 05 0e bd 3f a3 |..B.M..g..-...?.|
|
||||
00000220 8c 25 c1 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a |.%.3.......7z..z|
|
||||
00000230 c9 86 2e dd d7 11 69 7f 85 7c 56 de fb 31 78 2b |......i..|V..1x+|
|
||||
00000240 e4 c7 78 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 |..x.....N6$1{j.9|
|
||||
00000250 95 12 07 8f 2a 16 03 03 00 d7 0c 00 00 d3 03 00 |....*...........|
|
||||
00000260 17 41 04 c6 83 33 2b 47 c8 d2 a0 60 b9 6d 8e e8 |.A...3+G...`.m..|
|
||||
00000270 b2 6a 81 54 56 42 3c c9 72 17 7e a7 4c 5c 55 b9 |.j.TVB<.r.~.L\U.|
|
||||
00000280 65 f2 e8 3c 11 5a a1 06 75 ed b1 27 f7 42 88 5c |e..<.Z..u..'.B.\|
|
||||
00000290 a0 cb df 9d 0d fc 47 2d f3 b2 6b c6 92 9f 68 f9 |......G-..k...h.|
|
||||
000002a0 14 a3 df 06 03 00 8a 30 81 87 02 41 54 1e 82 48 |.......0...AT..H|
|
||||
000002b0 9f eb 40 47 20 81 25 ad b7 59 3b c6 97 0b 8d 1a |..@G .%..Y;.....|
|
||||
000002c0 40 97 dd 4a 3f 76 f6 d8 65 29 b7 a9 06 57 33 cb |@..J?v..e)...W3.|
|
||||
000002d0 a1 ef cf 02 55 17 81 ad 89 c1 9f 6b a0 23 f9 62 |....U......k.#.b|
|
||||
000002e0 4c d4 07 68 91 fe 6e c0 8d 40 eb 25 4a 02 42 01 |L..h..n..@.%J.B.|
|
||||
000002f0 18 94 e9 e1 41 ec 4b 84 8f 58 2d 3d 39 81 f2 e5 |....A.K..X-=9...|
|
||||
00000300 9b 9e d9 ab 5e 60 34 f1 67 12 6b 66 92 d3 6f 45 |....^`4.g.kf..oE|
|
||||
00000310 d7 5a ed a2 2a a5 80 4b 76 04 76 41 c2 95 24 8a |.Z..*..Kv.vA..$.|
|
||||
00000320 bd 1b 53 06 ff d9 d0 c1 de ac c2 22 d1 1a c4 84 |..S........"....|
|
||||
00000330 a1 16 03 03 00 04 0e 00 00 00 |..........|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
|
||||
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
|
||||
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
|
||||
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
|
||||
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
|
||||
00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
|
||||
00000060 00 00 00 00 00 00 5d 20 87 20 34 da 31 2e 3b 9b |......] . 4.1.;.|
|
||||
00000070 ba 60 10 1c 41 39 2e 09 a9 1e 9b c5 57 e6 30 2b |.`..A9......W.0+|
|
||||
00000080 11 bb 00 a7 b3 26 61 58 49 2b 7d 36 2f fc 91 47 |.....&aXI+}6/..G|
|
||||
00000090 8e 34 ad a0 f0 70 |.4...p|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 aa 04 00 00 a6 00 00 1c 20 00 a0 2f |............ ../|
|
||||
00000010 af 2f 7d 53 be 3c 62 3b 22 82 14 12 58 1c d6 54 |./}S.<b;"...X..T|
|
||||
00000020 d2 2a 8e 2e 73 27 92 f0 04 8e 57 fa b3 e1 1a 1b |.*..s'....W.....|
|
||||
00000030 c8 db 92 59 90 ef fa b7 42 a3 72 f2 2a c6 da 85 |...Y....B.r.*...|
|
||||
00000040 00 78 c2 18 11 4b 14 50 d9 16 ed 02 86 83 16 ec |.x...K.P........|
|
||||
00000050 79 86 39 5e 9b db 2d c2 7a 67 5a 3c 33 d0 b2 1d |y.9^..-.zgZ<3...|
|
||||
00000060 67 c9 be 29 af 6d e3 4e 33 eb b5 31 51 2a 17 42 |g..).m.N3..1Q*.B|
|
||||
00000070 9b a5 0d 7d 1e 72 e6 91 fc 66 78 d9 a2 46 99 65 |...}.r...fx..F.e|
|
||||
00000080 61 fd d6 bc 96 20 fa 1a c8 f1 01 3d 92 0e c7 df |a.... .....=....|
|
||||
00000090 a3 8a 39 ba 2b 67 b7 f2 71 e1 aa 61 2b 67 42 1e |..9.+g..q..a+gB.|
|
||||
000000a0 e6 ef b9 08 a1 c6 d8 38 78 60 0f 64 30 cf 13 14 |.......8x`.d0...|
|
||||
000000b0 03 03 00 01 01 16 03 03 00 40 d4 08 81 64 cd d2 |.........@...d..|
|
||||
000000c0 e4 c7 fe f0 61 fa 96 25 94 44 9e 25 41 72 db 90 |....a..%.D.%Ar..|
|
||||
000000d0 63 24 52 34 5e e9 43 0b 41 c1 96 b3 79 b0 81 b0 |c$R4^.C.A...y...|
|
||||
000000e0 cc f6 78 d9 97 68 c6 2b e2 34 9d 7f f3 d8 e6 1d |..x..h.+.4......|
|
||||
000000f0 29 ab 50 97 e1 a0 29 a1 3d 45 |).P...).=E|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
|
||||
00000010 00 00 00 00 00 80 ce c3 5d bb 87 a7 c6 63 96 65 |........]....c.e|
|
||||
00000020 89 0c c1 73 3d 50 b9 14 6c 3f 50 87 09 bc 95 8b |...s=P..l?P.....|
|
||||
00000030 cd 5b e3 bb 5d 15 03 03 00 30 00 00 00 00 00 00 |.[..]....0......|
|
||||
00000040 00 00 00 00 00 00 00 00 00 00 73 c7 6a a9 68 9f |..........s.j.h.|
|
||||
00000050 3e 98 99 da b3 7b aa 82 f7 59 04 cd 14 21 8d f4 |>....{...Y...!..|
|
||||
00000060 1e 83 b8 f4 4d 7b 4e e9 95 eb |....M{N...|
|
103
testdata/Client-TLSv12-UTLS-ECDHE-ECDSA-AES256-SHA-Android-22
vendored
Normal file
103
testdata/Client-TLSv12-UTLS-ECDHE-ECDSA-AES256-SHA-Android-22
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 c0 01 00 00 bc 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2a cc 14 |.............*..|
|
||||
00000030 cc 13 cc 15 c0 2f c0 2b 00 9e c0 14 c0 0a 00 39 |...../.+.......9|
|
||||
00000040 c0 13 c0 09 00 33 c0 11 c0 07 00 9c 00 35 00 2f |.....3.......5./|
|
||||
00000050 00 05 00 04 00 0a 00 ff 01 00 00 69 00 00 00 05 |...........i....|
|
||||
00000060 00 03 00 00 00 00 23 00 00 00 0d 00 16 00 14 06 |......#.........|
|
||||
00000070 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 |................|
|
||||
00000080 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 |............3t..|
|
||||
00000090 00 12 00 00 00 10 00 1b 00 19 08 68 74 74 70 2f |...........http/|
|
||||
000000a0 31 2e 31 06 73 70 64 79 2f 33 08 73 70 64 79 2f |1.1.spdy/3.spdy/|
|
||||
000000b0 33 2e 31 00 0b 00 02 01 00 00 0a 00 08 00 06 00 |3.1.............|
|
||||
000000c0 17 00 18 00 19 |.....|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 3d 02 00 00 39 03 03 98 7e 56 60 8a |....=...9...~V`.|
|
||||
00000010 9a d9 bc 4f 7c 55 c4 3a 5b 2a fa 68 aa aa 63 4e |...O|U.:[*.h..cN|
|
||||
00000020 b2 d0 05 d3 da ec 3a c8 ff f7 fe 00 c0 0a 00 00 |......:.........|
|
||||
00000030 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 23 |...............#|
|
||||
00000040 00 00 16 03 03 02 0e 0b 00 02 0a 00 02 07 00 02 |................|
|
||||
00000050 04 30 82 02 00 30 82 01 62 02 09 00 b8 bf 2d 47 |.0...0..b.....-G|
|
||||
00000060 a0 d2 eb f4 30 09 06 07 2a 86 48 ce 3d 04 01 30 |....0...*.H.=..0|
|
||||
00000070 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 |E1.0...U....AU1.|
|
||||
00000080 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 |0...U....Some-St|
|
||||
00000090 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e |ate1!0...U....In|
|
||||
000000a0 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 |ternet Widgits P|
|
||||
000000b0 74 79 20 4c 74 64 30 1e 17 0d 31 32 31 31 32 32 |ty Ltd0...121122|
|
||||
000000c0 31 35 30 36 33 32 5a 17 0d 32 32 31 31 32 30 31 |150632Z..2211201|
|
||||
000000d0 35 30 36 33 32 5a 30 45 31 0b 30 09 06 03 55 04 |50632Z0E1.0...U.|
|
||||
000000e0 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....|
|
||||
000000f0 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...|
|
||||
00000100 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi|
|
||||
00000110 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 9b |dgits Pty Ltd0..|
|
||||
00000120 30 10 06 07 2a 86 48 ce 3d 02 01 06 05 2b 81 04 |0...*.H.=....+..|
|
||||
00000130 00 23 03 81 86 00 04 00 c4 a1 ed be 98 f9 0b 48 |.#.............H|
|
||||
00000140 73 36 7e c3 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d |s6~..V.".=S.;M!=|
|
||||
00000150 cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 |.ku......&.....r|
|
||||
00000160 32 7c b3 64 2f 1c 90 bc ea 68 23 10 7e fe e3 25 |2|.d/....h#.~..%|
|
||||
00000170 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 |.H:i.(m.7...b...|
|
||||
00000180 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 |.pb....d1...1...|
|
||||
00000190 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 |h..#.vd?.\....XX|
|
||||
000001a0 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 |._p............0|
|
||||
000001b0 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 09 06 07 2a |f[f. .'...;0...*|
|
||||
000001c0 86 48 ce 3d 04 01 03 81 8c 00 30 81 88 02 42 01 |.H.=......0...B.|
|
||||
000001d0 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 ed 98 9d ae |..O..E.H}.......|
|
||||
000001e0 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 |Gp.^../...M.a@..|
|
||||
000001f0 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce |....~.~.v..;~.?.|
|
||||
00000200 fa 10 e2 59 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f |...Y.G-|..N....o|
|
||||
00000210 d0 02 42 01 4d fc be 67 13 9c 2d 05 0e bd 3f a3 |..B.M..g..-...?.|
|
||||
00000220 8c 25 c1 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a |.%.3.......7z..z|
|
||||
00000230 c9 86 2e dd d7 11 69 7f 85 7c 56 de fb 31 78 2b |......i..|V..1x+|
|
||||
00000240 e4 c7 78 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 |..x.....N6$1{j.9|
|
||||
00000250 95 12 07 8f 2a 16 03 03 00 d6 0c 00 00 d2 03 00 |....*...........|
|
||||
00000260 17 41 04 29 e7 e6 da c3 e5 0a 7a 1d 50 22 24 61 |.A.)......z.P"$a|
|
||||
00000270 69 fd 96 ef 00 8b 7c a2 b9 6d 2b b3 09 0c f4 27 |i.....|..m+....'|
|
||||
00000280 ad 4d 5e f1 d7 bc b2 97 5b c5 c7 15 3e c9 4e f7 |.M^.....[...>.N.|
|
||||
00000290 32 ed fc 74 2b 4c b6 e8 b2 e8 33 d2 b4 33 84 c1 |2..t+L....3..3..|
|
||||
000002a0 1d 29 ef 06 03 00 89 30 81 86 02 41 2b a7 bb a2 |.).....0...A+...|
|
||||
000002b0 3b 22 0f ef 6f e5 44 ca 42 58 ca 25 60 47 3a 82 |;"..o.D.BX.%`G:.|
|
||||
000002c0 a8 35 68 fc 83 6e 96 0e d9 11 fb 71 2a 5b e0 0f |.5h..n.....q*[..|
|
||||
000002d0 ff 2e 17 13 74 8c 2c 39 1a ea d6 f0 38 4b 19 26 |....t.,9....8K.&|
|
||||
000002e0 95 00 6b fa 61 b8 a9 dc 76 fc 5e da b4 02 41 6b |..k.a...v.^...Ak|
|
||||
000002f0 86 39 91 a8 66 03 87 08 d5 a5 a0 46 b1 61 3a d4 |.9..f......F.a:.|
|
||||
00000300 7b 1c 82 21 89 08 56 d0 d2 29 e8 51 b6 4f cc 34 |{..!..V..).Q.O.4|
|
||||
00000310 f5 cd 23 b6 f0 98 3c 1a 18 79 56 30 08 ea 06 da |..#...<..yV0....|
|
||||
00000320 12 ee 25 41 27 4e b1 ca 39 03 79 10 ce 31 0d ae |..%A'N..9.y..1..|
|
||||
00000330 16 03 03 00 04 0e 00 00 00 |.........|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
|
||||
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
|
||||
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
|
||||
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
|
||||
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
|
||||
00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
|
||||
00000060 00 00 00 00 00 00 20 ab 93 fa 57 6c 48 73 79 5f |...... ...WlHsy_|
|
||||
00000070 7a ff 50 f4 a1 9d ec 6a 79 1e 68 87 ea bb 20 0a |z.P....jy.h... .|
|
||||
00000080 24 97 fa 11 bf d9 ee 4c 2d 2b 80 88 11 23 a0 2e |$......L-+...#..|
|
||||
00000090 79 87 d3 45 e6 e7 |y..E..|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 aa 04 00 00 a6 00 00 1c 20 00 a0 49 |............ ..I|
|
||||
00000010 9a 8b 29 c7 e6 08 09 1a f9 61 99 ce 4b 4b 78 2e |..)......a..KKx.|
|
||||
00000020 3d 48 4c 02 d3 3a ff ae dc cb 73 aa 7f 29 aa ec |=HL..:....s..)..|
|
||||
00000030 e4 76 c0 b6 62 3e e7 a1 30 fa 0a f9 4d 9b ab 59 |.v..b>..0...M..Y|
|
||||
00000040 8f d0 50 ef ea bd 12 e4 ab 31 b5 21 88 62 47 0e |..P......1.!.bG.|
|
||||
00000050 37 37 e3 0a 88 ab 8b 88 d3 e9 70 6b 92 b3 72 1a |77........pk..r.|
|
||||
00000060 f2 9b cb 57 d2 97 69 0f a0 dd cc d0 70 0d 0a 66 |...W..i.....p..f|
|
||||
00000070 82 7f ea 9b b8 10 22 0e 37 93 6b e4 97 df 5d 9e |......".7.k...].|
|
||||
00000080 4b 23 b8 fb 79 ff 28 d4 ed 31 fd 9f 01 a7 21 1b |K#..y.(..1....!.|
|
||||
00000090 db 8b 6f bf c3 92 53 77 24 80 b4 3c f9 7a 2e a2 |..o...Sw$..<.z..|
|
||||
000000a0 09 8a 6d 6b 47 8b 8e 86 18 c0 fe 78 06 59 47 14 |..mkG......x.YG.|
|
||||
000000b0 03 03 00 01 01 16 03 03 00 40 78 f8 fb c1 2c 7d |.........@x...,}|
|
||||
000000c0 18 5d 8a 94 f6 e9 ea c4 6f 71 50 a6 ee 62 3a 7d |.]......oqP..b:}|
|
||||
000000d0 25 ef c2 6e 11 e3 04 70 76 6b 30 97 ba a1 9d 49 |%..n...pvk0....I|
|
||||
000000e0 f6 47 64 60 8a ba ea 52 16 10 8d 9a 3c 56 1b 13 |.Gd`...R....<V..|
|
||||
000000f0 1e 2c a0 f9 f7 e5 df a1 fc f8 |.,........|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
|
||||
00000010 00 00 00 00 00 5f 1b 2b 17 f6 a2 53 36 49 ad e0 |....._.+...S6I..|
|
||||
00000020 15 dd 38 f0 db ed c4 c2 31 76 b2 4b 11 b9 3f 72 |..8.....1v.K..?r|
|
||||
00000030 48 f6 cd 2c c9 15 03 03 00 30 00 00 00 00 00 00 |H..,.....0......|
|
||||
00000040 00 00 00 00 00 00 00 00 00 00 29 31 29 ca 84 78 |..........)1)..x|
|
||||
00000050 c8 ed 7d 56 4d d2 d2 0d 47 f0 5a 7c 1f aa 6c d6 |..}VM...G.Z|..l.|
|
||||
00000060 3b 41 b5 26 9d 05 f3 28 2f fe |;A.&...(/.|
|
102
testdata/Client-TLSv12-UTLS-ECDHE-RSA-AES128-GCM-SHA256-Android-22
vendored
Normal file
102
testdata/Client-TLSv12-UTLS-ECDHE-RSA-AES128-GCM-SHA256-Android-22
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 c0 01 00 00 bc 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2a cc 14 |.............*..|
|
||||
00000030 cc 13 cc 15 c0 2f c0 2b 00 9e c0 14 c0 0a 00 39 |...../.+.......9|
|
||||
00000040 c0 13 c0 09 00 33 c0 11 c0 07 00 9c 00 35 00 2f |.....3.......5./|
|
||||
00000050 00 05 00 04 00 0a 00 ff 01 00 00 69 00 00 00 05 |...........i....|
|
||||
00000060 00 03 00 00 00 00 23 00 00 00 0d 00 16 00 14 06 |......#.........|
|
||||
00000070 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 |................|
|
||||
00000080 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 |............3t..|
|
||||
00000090 00 12 00 00 00 10 00 1b 00 19 08 68 74 74 70 2f |...........http/|
|
||||
000000a0 31 2e 31 06 73 70 64 79 2f 33 08 73 70 64 79 2f |1.1.spdy/3.spdy/|
|
||||
000000b0 33 2e 31 00 0b 00 02 01 00 00 0a 00 08 00 06 00 |3.1.............|
|
||||
000000c0 17 00 18 00 19 |.....|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 3d 02 00 00 39 03 03 83 de 75 c9 5f |....=...9....u._|
|
||||
00000010 67 39 d4 57 19 ca d9 1c 3a ff 53 d8 aa 5a 4f 33 |g9.W....:.S..ZO3|
|
||||
00000020 4e e7 aa ca 8d e4 1a cf 5a 98 e0 00 c0 2f 00 00 |N.......Z..../..|
|
||||
00000030 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 23 |...............#|
|
||||
00000040 00 00 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 |......Y...U..R..|
|
||||
00000050 4f 30 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 |O0..K0..........|
|
||||
00000060 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 |....?.[..0...*.H|
|
||||
00000070 86 f7 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 |........0.1.0...|
|
||||
00000080 55 04 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 |U....Go1.0...U..|
|
||||
00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 |..Go Root0...160|
|
||||
000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
|
||||
000000b0 30 31 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 |01000000Z0.1.0..|
|
||||
000000c0 03 55 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 |.U....Go1.0...U.|
|
||||
000000d0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
|
||||
000000e0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
|
||||
000000f0 81 00 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab |...F}...'.H..(!.|
|
||||
00000100 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d |~...]..RE.z6G...|
|
||||
00000110 92 42 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd |.B[.....y.@.Om..|
|
||||
00000120 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a |+.....g....."8.J|
|
||||
00000130 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 |.ts+.4......t{.X|
|
||||
00000140 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c |.la<..A..++$#w[.|
|
||||
00000150 3b bd 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 |;.u]. T..c...$..|
|
||||
00000160 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 |..P....C...ub...|
|
||||
00000170 52 d7 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |R.........0..0..|
|
||||
00000180 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
|
||||
00000190 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
|
||||
000001a0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
|
||||
000001b0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
|
||||
000001c0 0e 04 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d |.........CC>I..m|
|
||||
000001d0 b6 80 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 |....`0...U.#..0.|
|
||||
000001e0 80 10 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab |..H.IM.~.1......|
|
||||
000001f0 6e 7b 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |n{0...U....0...e|
|
||||
00000200 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
|
||||
00000210 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
|
||||
00000220 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed |.0.@+[P.a...SX..|
|
||||
00000230 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 |.(.X..8....1Z..f|
|
||||
00000240 3d 43 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a |=C.-...... d8.$:|
|
||||
00000250 00 bc cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 |....}.@ ._...a..|
|
||||
00000260 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed |v......\.....l..|
|
||||
00000270 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 |s..Cw.......@.a.|
|
||||
00000280 4c 72 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 |Lr+...F..M...>..|
|
||||
00000290 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 |.B...=.`.\!.;...|
|
||||
000002a0 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 2c 27 |............A.,'|
|
||||
000002b0 ff f2 bb 63 4b 54 d6 8a 89 9a f7 9f 02 6c 14 85 |...cKT.......l..|
|
||||
000002c0 c2 a2 a7 cd 9d 79 5a 53 fb 4c a4 5e fc b2 9d 12 |.....yZS.L.^....|
|
||||
000002d0 19 c7 63 d7 85 3b 1c 24 ce ea 76 24 c3 74 73 55 |..c..;.$..v$.tsU|
|
||||
000002e0 29 fa cc 24 15 9a db f6 4d 5a 2c 2c d8 cc 06 01 |)..$....MZ,,....|
|
||||
000002f0 00 80 b1 49 d5 7c 2d 46 2d c5 56 0c 74 72 a7 8f |...I.|-F-.V.tr..|
|
||||
00000300 2a 7b 5f 72 55 b8 36 dd eb 04 8b f7 ca 84 b6 ce |*{_rU.6.........|
|
||||
00000310 c9 a0 f4 c5 e1 7f d4 9c ff e5 20 ff eb 28 cb be |.......... ..(..|
|
||||
00000320 21 cb 85 ef 5b e3 60 da 38 39 57 6b 8c 55 40 e1 |!...[.`.89Wk.U@.|
|
||||
00000330 84 6a d2 87 20 31 39 17 2e 09 e9 99 51 42 97 23 |.j.. 19.....QB.#|
|
||||
00000340 c8 72 5b 82 70 6a ca 0e 19 28 51 ae 94 81 c8 6a |.r[.pj...(Q....j|
|
||||
00000350 fe 6d 3d 9e cd e4 55 03 84 47 c8 41 91 1c dc e4 |.m=...U..G.A....|
|
||||
00000360 3b 77 44 6c 88 7e 6c 28 98 e1 57 e0 b4 fa 6c b1 |;wDl.~l(..W...l.|
|
||||
00000370 2f c8 16 03 03 00 04 0e 00 00 00 |/..........|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
|
||||
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
|
||||
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
|
||||
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
|
||||
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
|
||||
00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 01 ff |.....(..........|
|
||||
00000060 f8 92 3a 63 d4 c5 e9 17 62 88 6a c3 26 72 58 76 |..:c....b.j.&rXv|
|
||||
00000070 ca 63 8f 0d 1b f1 af 75 7c cd 93 35 a3 54 |.c.....u|..5.T|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 aa 04 00 00 a6 00 00 1c 20 00 a0 3c |............ ..<|
|
||||
00000010 f5 21 c4 db 76 eb 6e c6 76 ff b0 01 de 03 ae c8 |.!..v.n.v.......|
|
||||
00000020 2d d2 3a 76 a8 53 75 e1 0b 23 c8 82 23 90 f9 51 |-.:v.Su..#..#..Q|
|
||||
00000030 f5 cb 47 63 38 e7 8f d7 9e e0 88 1d f3 63 b5 a2 |..Gc8........c..|
|
||||
00000040 ed 27 90 02 21 df 0b e1 f3 3c b7 dd e0 d8 34 44 |.'..!....<....4D|
|
||||
00000050 9f 13 6f 8a a0 01 91 ce 7e d1 3f b3 74 2c f6 3a |..o.....~.?.t,.:|
|
||||
00000060 91 1b 98 86 62 d1 56 f7 3f 68 47 25 6a ed a0 ca |....b.V.?hG%j...|
|
||||
00000070 c8 81 1a ae 94 15 db 3c db ee 25 dd 4c 6f 32 98 |.......<..%.Lo2.|
|
||||
00000080 fa a0 bf 37 9b 9c 3b f1 18 94 4a 02 c1 d4 c6 67 |...7..;...J....g|
|
||||
00000090 22 24 22 e8 d9 24 ad 7f 6c 34 37 50 3f c9 ac 45 |"$"..$..l47P?..E|
|
||||
000000a0 f9 8e 88 d0 41 ff e8 8f c6 83 38 eb 9d 65 f1 14 |....A.....8..e..|
|
||||
000000b0 03 03 00 01 01 16 03 03 00 28 03 46 d2 af 96 b2 |.........(.F....|
|
||||
000000c0 2d 6a 2e 24 be 99 f2 d7 53 e8 cc 5d 33 50 19 25 |-j.$....S..]3P.%|
|
||||
000000d0 0f 4d 8a ec 8d 77 d5 58 67 be cd b6 80 5c f8 5d |.M...w.Xg....\.]|
|
||||
000000e0 a1 4e |.N|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 66 61 98 |.............fa.|
|
||||
00000010 10 ed c0 5d 9d 1d 0e 9f 35 c9 50 fc 4a d9 39 06 |...]....5.P.J.9.|
|
||||
00000020 63 73 e7 15 03 03 00 1a 00 00 00 00 00 00 00 02 |cs..............|
|
||||
00000030 5b 0c 8d f5 e0 88 97 5e ba a7 78 cc f1 f2 69 19 |[......^..x...i.|
|
||||
00000040 44 83 |D.|
|
107
testdata/Client-TLSv12-UTLS-ECDHE-RSA-AES128-SHA-Android-22
vendored
Normal file
107
testdata/Client-TLSv12-UTLS-ECDHE-RSA-AES128-SHA-Android-22
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 c0 01 00 00 bc 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2a cc 14 |.............*..|
|
||||
00000030 cc 13 cc 15 c0 2f c0 2b 00 9e c0 14 c0 0a 00 39 |...../.+.......9|
|
||||
00000040 c0 13 c0 09 00 33 c0 11 c0 07 00 9c 00 35 00 2f |.....3.......5./|
|
||||
00000050 00 05 00 04 00 0a 00 ff 01 00 00 69 00 00 00 05 |...........i....|
|
||||
00000060 00 03 00 00 00 00 23 00 00 00 0d 00 16 00 14 06 |......#.........|
|
||||
00000070 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 |................|
|
||||
00000080 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 |............3t..|
|
||||
00000090 00 12 00 00 00 10 00 1b 00 19 08 68 74 74 70 2f |...........http/|
|
||||
000000a0 31 2e 31 06 73 70 64 79 2f 33 08 73 70 64 79 2f |1.1.spdy/3.spdy/|
|
||||
000000b0 33 2e 31 00 0b 00 02 01 00 00 0a 00 08 00 06 00 |3.1.............|
|
||||
000000c0 17 00 18 00 19 |.....|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 3d 02 00 00 39 03 03 a5 6d 48 df 33 |....=...9...mH.3|
|
||||
00000010 e4 75 4b 37 b4 36 84 c4 ff 32 b0 3f cb ff 3f d6 |.uK7.6...2.?..?.|
|
||||
00000020 a6 f6 b2 a0 d7 84 f6 c0 70 d0 ad 00 c0 13 00 00 |........p.......|
|
||||
00000030 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 23 |...............#|
|
||||
00000040 00 00 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 |......Y...U..R..|
|
||||
00000050 4f 30 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 |O0..K0..........|
|
||||
00000060 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 |....?.[..0...*.H|
|
||||
00000070 86 f7 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 |........0.1.0...|
|
||||
00000080 55 04 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 |U....Go1.0...U..|
|
||||
00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 |..Go Root0...160|
|
||||
000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
|
||||
000000b0 30 31 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 |01000000Z0.1.0..|
|
||||
000000c0 03 55 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 |.U....Go1.0...U.|
|
||||
000000d0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
|
||||
000000e0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
|
||||
000000f0 81 00 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab |...F}...'.H..(!.|
|
||||
00000100 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d |~...]..RE.z6G...|
|
||||
00000110 92 42 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd |.B[.....y.@.Om..|
|
||||
00000120 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a |+.....g....."8.J|
|
||||
00000130 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 |.ts+.4......t{.X|
|
||||
00000140 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c |.la<..A..++$#w[.|
|
||||
00000150 3b bd 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 |;.u]. T..c...$..|
|
||||
00000160 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 |..P....C...ub...|
|
||||
00000170 52 d7 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |R.........0..0..|
|
||||
00000180 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
|
||||
00000190 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
|
||||
000001a0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
|
||||
000001b0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
|
||||
000001c0 0e 04 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d |.........CC>I..m|
|
||||
000001d0 b6 80 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 |....`0...U.#..0.|
|
||||
000001e0 80 10 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab |..H.IM.~.1......|
|
||||
000001f0 6e 7b 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |n{0...U....0...e|
|
||||
00000200 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
|
||||
00000210 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
|
||||
00000220 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed |.0.@+[P.a...SX..|
|
||||
00000230 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 |.(.X..8....1Z..f|
|
||||
00000240 3d 43 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a |=C.-...... d8.$:|
|
||||
00000250 00 bc cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 |....}.@ ._...a..|
|
||||
00000260 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed |v......\.....l..|
|
||||
00000270 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 |s..Cw.......@.a.|
|
||||
00000280 4c 72 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 |Lr+...F..M...>..|
|
||||
00000290 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 |.B...=.`.\!.;...|
|
||||
000002a0 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1c fd |............A...|
|
||||
000002b0 f6 6e e5 35 c4 18 ae c3 d9 4d 97 de 78 f0 44 73 |.n.5.....M..x.Ds|
|
||||
000002c0 a8 76 85 0e 41 5c 49 5b 10 5b 90 c4 7b 9b f9 3c |.v..A\I[.[..{..<|
|
||||
000002d0 9c dd 42 26 4f 47 1b 09 56 b5 19 27 a4 21 9c 2d |..B&OG..V..'.!.-|
|
||||
000002e0 00 4d 92 1c 6c ed 00 9b 31 1b cb 90 ad e4 06 01 |.M..l...1.......|
|
||||
000002f0 00 80 67 1d 29 1a 14 5a cb be b5 f8 11 a7 93 5e |..g.)..Z.......^|
|
||||
00000300 da e2 c2 81 ed 3a 33 c0 32 c4 05 c5 75 5f de 15 |.....:3.2...u_..|
|
||||
00000310 f3 b9 46 95 aa ee c7 67 34 2b 40 cc 22 e1 12 a4 |..F....g4+@."...|
|
||||
00000320 a6 59 29 e7 54 30 f8 8e 08 e6 38 1d 37 f4 50 08 |.Y).T0....8.7.P.|
|
||||
00000330 d3 3d 28 9b 9c c7 c7 ab 2c 6a 6e db 2e 57 84 e8 |.=(.....,jn..W..|
|
||||
00000340 a5 77 97 ca d8 29 77 94 93 04 6f da 50 fc 41 c4 |.w...)w...o.P.A.|
|
||||
00000350 d6 d7 1a ec b9 66 2a ed 17 4f 01 d2 94 7f 82 e4 |.....f*..O......|
|
||||
00000360 e2 ea c5 30 12 b5 1e c3 44 cc 03 ba 34 12 47 e8 |...0....D...4.G.|
|
||||
00000370 9e fc 16 03 03 00 04 0e 00 00 00 |...........|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
|
||||
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
|
||||
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
|
||||
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
|
||||
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
|
||||
00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
|
||||
00000060 00 00 00 00 00 00 bf 98 78 3b 51 81 70 2d 1c 5d |........x;Q.p-.]|
|
||||
00000070 a6 1b ec ef 0a ae a0 52 dd 25 2a 26 45 29 58 93 |.......R.%*&E)X.|
|
||||
00000080 59 b1 32 eb 83 8e 41 44 0d 57 b7 93 2a 13 c5 e2 |Y.2...AD.W..*...|
|
||||
00000090 a1 7c 47 87 b2 0a |.|G...|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 aa 04 00 00 a6 00 00 1c 20 00 a0 ec |............ ...|
|
||||
00000010 56 10 cc 76 e5 78 39 22 8e 76 53 03 db 34 5e e3 |V..v.x9".vS..4^.|
|
||||
00000020 a3 dd e5 fb 3f ba 38 a5 e3 8d 87 7a f3 b0 88 2d |....?.8....z...-|
|
||||
00000030 81 ca 7c 0c da 56 5d 42 1e 45 a5 41 9d 52 3c 98 |..|..V]B.E.A.R<.|
|
||||
00000040 bb 42 ad 90 51 06 95 ab 2b 7c f0 9f fa 54 1f 6d |.B..Q...+|...T.m|
|
||||
00000050 55 a3 5e 77 1a b1 41 0e 30 4d 6c 06 af cf 13 99 |U.^w..A.0Ml.....|
|
||||
00000060 89 47 40 77 f3 5f 15 81 e9 05 8d 23 31 00 a0 f4 |.G@w._.....#1...|
|
||||
00000070 ab 02 90 03 f5 67 cb 93 9d f0 28 a6 0f 1d 7b ca |.....g....(...{.|
|
||||
00000080 71 2a 59 2e b1 6d 32 de 11 99 11 2e 58 f3 c5 de |q*Y..m2.....X...|
|
||||
00000090 cb b8 d3 35 b9 53 5a 44 c9 49 d0 a6 f8 d0 7b aa |...5.SZD.I....{.|
|
||||
000000a0 f8 95 38 5b 61 78 21 1c be 2a c8 01 20 03 be 14 |..8[ax!..*.. ...|
|
||||
000000b0 03 03 00 01 01 16 03 03 00 40 a0 82 06 07 49 de |.........@....I.|
|
||||
000000c0 e9 85 67 1b 26 20 7c 1b ef 0c c8 68 c3 7b 81 8e |..g.& |....h.{..|
|
||||
000000d0 e4 a7 4e 94 ff 5e 45 ce 6a a3 7a 29 ab 4c 28 7f |..N..^E.j.z).L(.|
|
||||
000000e0 69 ec da ca 4f 3e 98 1c 8a 41 5f ba 7d 2d 13 28 |i...O>...A_.}-.(|
|
||||
000000f0 a2 72 a3 14 da 98 7a 6c ef 77 |.r....zl.w|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
|
||||
00000010 00 00 00 00 00 a9 57 aa 50 33 9b 04 8d db 4b cd |......W.P3....K.|
|
||||
00000020 0d e6 ca fc e8 58 24 d1 f4 d7 13 69 5a d0 a8 2b |.....X$....iZ..+|
|
||||
00000030 ec ea ab 1b d2 15 03 03 00 30 00 00 00 00 00 00 |.........0......|
|
||||
00000040 00 00 00 00 00 00 00 00 00 00 3c b1 d0 db c9 4a |..........<....J|
|
||||
00000050 fd a3 8e 90 cd 86 49 a5 9d c6 95 bf 98 59 45 48 |......I......YEH|
|
||||
00000060 ad 08 5c ea 60 24 fa 9e 6c d6 |..\.`$..l.|
|
107
testdata/Client-TLSv12-UTLS-ECDHE-RSA-AES256-SHA-Android-22
vendored
Normal file
107
testdata/Client-TLSv12-UTLS-ECDHE-RSA-AES256-SHA-Android-22
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
>>> Flow 1 (client to server)
|
||||
00000000 16 03 01 00 c0 01 00 00 bc 03 03 00 00 00 00 00 |................|
|
||||
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
||||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2a cc 14 |.............*..|
|
||||
00000030 cc 13 cc 15 c0 2f c0 2b 00 9e c0 14 c0 0a 00 39 |...../.+.......9|
|
||||
00000040 c0 13 c0 09 00 33 c0 11 c0 07 00 9c 00 35 00 2f |.....3.......5./|
|
||||
00000050 00 05 00 04 00 0a 00 ff 01 00 00 69 00 00 00 05 |...........i....|
|
||||
00000060 00 03 00 00 00 00 23 00 00 00 0d 00 16 00 14 06 |......#.........|
|
||||
00000070 01 06 03 05 01 05 03 04 01 04 03 03 01 03 03 02 |................|
|
||||
00000080 01 02 03 00 05 00 05 01 00 00 00 00 33 74 00 00 |............3t..|
|
||||
00000090 00 12 00 00 00 10 00 1b 00 19 08 68 74 74 70 2f |...........http/|
|
||||
000000a0 31 2e 31 06 73 70 64 79 2f 33 08 73 70 64 79 2f |1.1.spdy/3.spdy/|
|
||||
000000b0 33 2e 31 00 0b 00 02 01 00 00 0a 00 08 00 06 00 |3.1.............|
|
||||
000000c0 17 00 18 00 19 |.....|
|
||||
>>> Flow 2 (server to client)
|
||||
00000000 16 03 03 00 3d 02 00 00 39 03 03 8b 3e 63 de d4 |....=...9...>c..|
|
||||
00000010 76 f3 88 6f 0e 35 0f 6a 18 03 2a b1 10 11 82 ea |v..o.5.j..*.....|
|
||||
00000020 a5 c2 8b 6c 77 35 01 71 13 b7 f2 00 c0 14 00 00 |...lw5.q........|
|
||||
00000030 11 ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 23 |...............#|
|
||||
00000040 00 00 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 |......Y...U..R..|
|
||||
00000050 4f 30 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 |O0..K0..........|
|
||||
00000060 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 |....?.[..0...*.H|
|
||||
00000070 86 f7 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 |........0.1.0...|
|
||||
00000080 55 04 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 |U....Go1.0...U..|
|
||||
00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 |..Go Root0...160|
|
||||
000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
|
||||
000000b0 30 31 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 |01000000Z0.1.0..|
|
||||
000000c0 03 55 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 |.U....Go1.0...U.|
|
||||
000000d0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
|
||||
000000e0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
|
||||
000000f0 81 00 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab |...F}...'.H..(!.|
|
||||
00000100 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d |~...]..RE.z6G...|
|
||||
00000110 92 42 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd |.B[.....y.@.Om..|
|
||||
00000120 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a |+.....g....."8.J|
|
||||
00000130 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 |.ts+.4......t{.X|
|
||||
00000140 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c |.la<..A..++$#w[.|
|
||||
00000150 3b bd 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 |;.u]. T..c...$..|
|
||||
00000160 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 |..P....C...ub...|
|
||||
00000170 52 d7 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |R.........0..0..|
|
||||
00000180 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
|
||||
00000190 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
|
||||
000001a0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
|
||||
000001b0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
|
||||
000001c0 0e 04 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d |.........CC>I..m|
|
||||
000001d0 b6 80 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 |....`0...U.#..0.|
|
||||
000001e0 80 10 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab |..H.IM.~.1......|
|
||||
000001f0 6e 7b 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |n{0...U....0...e|
|
||||
00000200 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
|
||||
00000210 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
|
||||
00000220 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed |.0.@+[P.a...SX..|
|
||||
00000230 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 |.(.X..8....1Z..f|
|
||||
00000240 3d 43 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a |=C.-...... d8.$:|
|
||||
00000250 00 bc cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 |....}.@ ._...a..|
|
||||
00000260 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed |v......\.....l..|
|
||||
00000270 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 |s..Cw.......@.a.|
|
||||
00000280 4c 72 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 |Lr+...F..M...>..|
|
||||
00000290 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 |.B...=.`.\!.;...|
|
||||
000002a0 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 2e c8 |............A...|
|
||||
000002b0 2d cc 7a 32 59 32 54 a7 2a fc bd 80 b3 b0 29 a9 |-.z2Y2T.*.....).|
|
||||
000002c0 a0 a8 3f 9d 5e 35 c5 7c 3d a2 7e 02 85 56 06 66 |..?.^5.|=.~..V.f|
|
||||
000002d0 e4 6a 50 bd d1 6a b9 2f 83 cf bb 95 a8 47 15 0b |.jP..j./.....G..|
|
||||
000002e0 96 63 0d eb 3b 51 cf e0 f4 a9 ce 85 b7 0c 06 01 |.c..;Q..........|
|
||||
000002f0 00 80 53 54 11 b7 1b b4 bd 59 7e 65 04 8a 12 7b |..ST.....Y~e...{|
|
||||
00000300 c1 de 4f 71 32 a8 b8 21 08 05 e1 33 bf 83 c4 3e |..Oq2..!...3...>|
|
||||
00000310 27 10 e7 5b 16 7a ac 6b ee a1 92 ea ea bb 22 5b |'..[.z.k......"[|
|
||||
00000320 6c 68 ce b1 e8 a2 51 a8 07 1c c0 98 fa 3c 01 59 |lh....Q......<.Y|
|
||||
00000330 9e f0 ee 13 51 7c 09 78 d2 33 7b 2b 8c da 85 f1 |....Q|.x.3{+....|
|
||||
00000340 96 05 8e ae 4d 92 51 1f fb 48 03 66 99 28 cb 2e |....M.Q..H.f.(..|
|
||||
00000350 9f 63 47 51 ba 5b 28 d0 3b 8a 9e d9 c8 51 a8 af |.cGQ.[(.;....Q..|
|
||||
00000360 dd a6 2e d5 84 0d c2 e4 f8 f4 2b 97 b1 ba 7d e8 |..........+...}.|
|
||||
00000370 45 0d 16 03 03 00 04 0e 00 00 00 |E..........|
|
||||
>>> Flow 3 (client to server)
|
||||
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
|
||||
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
|
||||
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
|
||||
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
|
||||
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
|
||||
00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........|
|
||||
00000060 00 00 00 00 00 00 77 04 90 a4 32 b4 73 6b 41 4e |......w...2.skAN|
|
||||
00000070 7b 25 a4 62 24 d6 8d 43 0d 45 19 51 99 53 f5 45 |{%.b$..C.E.Q.S.E|
|
||||
00000080 76 26 5f 32 d0 ff cd 0f 86 a3 0e f8 7e 2f 09 8b |v&_2........~/..|
|
||||
00000090 2e 1c 03 9c 25 f4 |....%.|
|
||||
>>> Flow 4 (server to client)
|
||||
00000000 16 03 03 00 aa 04 00 00 a6 00 00 1c 20 00 a0 79 |............ ..y|
|
||||
00000010 f1 01 24 4b 47 9e 51 dc 90 98 cc 88 09 66 2b c0 |..$KG.Q......f+.|
|
||||
00000020 ca b4 fc be 56 da d1 0c 86 61 91 a2 36 e2 55 91 |....V....a..6.U.|
|
||||
00000030 f7 a2 d5 8c e8 4c 76 4b 3e 19 b2 33 fd 43 c1 5c |.....LvK>..3.C.\|
|
||||
00000040 2a 67 9d 21 c3 2c 65 52 0e 6b bb 5f ca c6 1a fe |*g.!.,eR.k._....|
|
||||
00000050 29 1e 42 10 56 4b 7b 58 93 72 5a 78 13 4c 42 cc |).B.VK{X.rZx.LB.|
|
||||
00000060 17 f7 33 06 41 b7 f3 49 f0 45 f7 0a ca 16 d7 8c |..3.A..I.E......|
|
||||
00000070 f5 60 ea 17 cf a0 b5 c2 3a c3 6b e6 65 75 48 c4 |.`......:.k.euH.|
|
||||
00000080 76 37 37 28 ca f9 ae 43 ca 64 d1 33 21 02 fd 95 |v77(...C.d.3!...|
|
||||
00000090 f1 75 15 ea b1 44 94 61 21 c4 4b 33 38 b9 cf cb |.u...D.a!.K38...|
|
||||
000000a0 29 8f 91 12 25 11 93 d3 c3 5e 2d 48 fa ac 1b 14 |)...%....^-H....|
|
||||
000000b0 03 03 00 01 01 16 03 03 00 40 f8 ca ea 95 92 6b |.........@.....k|
|
||||
000000c0 c5 51 28 f6 01 e1 f1 77 f2 b8 55 3c f2 9b dd 4f |.Q(....w..U<...O|
|
||||
000000d0 82 6d 16 17 02 bf ba 05 c7 bf 16 b2 68 fe d8 e3 |.m..........h...|
|
||||
000000e0 b7 ad 2a 49 87 15 b4 25 7b bf 15 f4 2c 6b cd e9 |..*I...%{...,k..|
|
||||
000000f0 7e ba c9 22 88 b4 d7 fa 3a 4b |~.."....:K|
|
||||
>>> Flow 5 (client to server)
|
||||
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
|
||||
00000010 00 00 00 00 00 68 8e 89 29 68 99 fb 6e 8b e3 fb |.....h..)h..n...|
|
||||
00000020 7b 1f b1 d3 ca 0b 0c 6f 23 dd ca 02 0a cf 93 11 |{......o#.......|
|
||||
00000030 fc e7 3d 18 ce 15 03 03 00 30 00 00 00 00 00 00 |..=......0......|
|
||||
00000040 00 00 00 00 00 00 00 00 00 00 f6 50 1a 7b 60 a1 |...........P.{`.|
|
||||
00000050 8c 41 63 4d 0f cc d5 94 81 d9 e2 7d 43 1d 5f 7a |.AcM.......}C._z|
|
||||
00000060 c1 9b d9 8d f7 4d 1e d0 7d 96 |.....M..}.|
|
193
testenv/testenv.go
Normal file
193
testenv/testenv.go
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package testenv provides information about what functionality
|
||||
// is available in different testing environments run by the Go team.
|
||||
//
|
||||
// It is an internal package because these details are specific
|
||||
// to the Go team's test setup (on build.golang.org) and not
|
||||
// fundamental to tests in general.
|
||||
package testenv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Builder reports the name of the builder running this test
|
||||
// (for example, "linux-amd64" or "windows-386-gce").
|
||||
// If the test is not running on the build infrastructure,
|
||||
// Builder returns the empty string.
|
||||
func Builder() string {
|
||||
return os.Getenv("GO_BUILDER_NAME")
|
||||
}
|
||||
|
||||
// HasGoBuild reports whether the current system can build programs with ``go build''
|
||||
// and then run them with os.StartProcess or exec.Command.
|
||||
func HasGoBuild() bool {
|
||||
switch runtime.GOOS {
|
||||
case "android", "nacl":
|
||||
return false
|
||||
case "darwin":
|
||||
if strings.HasPrefix(runtime.GOARCH, "arm") {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MustHaveGoBuild checks that the current system can build programs with ``go build''
|
||||
// and then run them with os.StartProcess or exec.Command.
|
||||
// If not, MustHaveGoBuild calls t.Skip with an explanation.
|
||||
func MustHaveGoBuild(t *testing.T) {
|
||||
if !HasGoBuild() {
|
||||
t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
// HasGoRun reports whether the current system can run programs with ``go run.''
|
||||
func HasGoRun() bool {
|
||||
// For now, having go run and having go build are the same.
|
||||
return HasGoBuild()
|
||||
}
|
||||
|
||||
// MustHaveGoRun checks that the current system can run programs with ``go run.''
|
||||
// If not, MustHaveGoRun calls t.Skip with an explanation.
|
||||
func MustHaveGoRun(t *testing.T) {
|
||||
if !HasGoRun() {
|
||||
t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
// GoToolPath reports the path to the Go tool.
|
||||
// It is a convenience wrapper around GoTool.
|
||||
// If the tool is unavailable GoToolPath calls t.Skip.
|
||||
// If the tool should be available and isn't, GoToolPath calls t.Fatal.
|
||||
func GoToolPath(t *testing.T) string {
|
||||
MustHaveGoBuild(t)
|
||||
path, err := GoTool()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// GoTool reports the path to the Go tool.
|
||||
func GoTool() (string, error) {
|
||||
if !HasGoBuild() {
|
||||
return "", errors.New("platform cannot run go tool")
|
||||
}
|
||||
var exeSuffix string
|
||||
if runtime.GOOS == "windows" {
|
||||
exeSuffix = ".exe"
|
||||
}
|
||||
path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
goBin, err := exec.LookPath("go" + exeSuffix)
|
||||
if err != nil {
|
||||
return "", errors.New("cannot find go tool: " + err.Error())
|
||||
}
|
||||
return goBin, nil
|
||||
}
|
||||
|
||||
// HasExec reports whether the current system can start new processes
|
||||
// using os.StartProcess or (more commonly) exec.Command.
|
||||
func HasExec() bool {
|
||||
switch runtime.GOOS {
|
||||
case "nacl":
|
||||
return false
|
||||
case "darwin":
|
||||
if strings.HasPrefix(runtime.GOARCH, "arm") {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MustHaveExec checks that the current system can start new processes
|
||||
// using os.StartProcess or (more commonly) exec.Command.
|
||||
// If not, MustHaveExec calls t.Skip with an explanation.
|
||||
func MustHaveExec(t *testing.T) {
|
||||
if !HasExec() {
|
||||
t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
// HasExternalNetwork reports whether the current system can use
|
||||
// external (non-localhost) networks.
|
||||
func HasExternalNetwork() bool {
|
||||
return !testing.Short()
|
||||
}
|
||||
|
||||
// MustHaveExternalNetwork checks that the current system can use
|
||||
// external (non-localhost) networks.
|
||||
// If not, MustHaveExternalNetwork calls t.Skip with an explanation.
|
||||
func MustHaveExternalNetwork(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skipf("skipping test: no external network in -short mode")
|
||||
}
|
||||
}
|
||||
|
||||
var haveCGO bool
|
||||
|
||||
// MustHaveCGO calls t.Skip if cgo is not available.
|
||||
func MustHaveCGO(t *testing.T) {
|
||||
if !haveCGO {
|
||||
t.Skipf("skipping test: no cgo")
|
||||
}
|
||||
}
|
||||
|
||||
// HasSymlink reports whether the current system can use os.Symlink.
|
||||
func HasSymlink() bool {
|
||||
ok, _ := hasSymlink()
|
||||
return ok
|
||||
}
|
||||
|
||||
// MustHaveSymlink reports whether the current system can use os.Symlink.
|
||||
// If not, MustHaveSymlink calls t.Skip with an explanation.
|
||||
func MustHaveSymlink(t *testing.T) {
|
||||
ok, reason := hasSymlink()
|
||||
if !ok {
|
||||
t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason)
|
||||
}
|
||||
}
|
||||
|
||||
// HasLink reports whether the current system can use os.Link.
|
||||
func HasLink() bool {
|
||||
// From Android release M (Marshmallow), hard linking files is blocked
|
||||
// and an attempt to call link() on a file will return EACCES.
|
||||
// - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
|
||||
return runtime.GOOS != "plan9" && runtime.GOOS != "android"
|
||||
}
|
||||
|
||||
// MustHaveLink reports whether the current system can use os.Link.
|
||||
// If not, MustHaveLink calls t.Skip with an explanation.
|
||||
func MustHaveLink(t *testing.T) {
|
||||
if !HasLink() {
|
||||
t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
|
||||
|
||||
func SkipFlaky(t *testing.T, issue int) {
|
||||
if !*flaky {
|
||||
t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue)
|
||||
}
|
||||
}
|
||||
|
||||
func SkipFlakyNet(t *testing.T) {
|
||||
if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v {
|
||||
t.Skip("skipping test on builder known to have frequent network failures")
|
||||
}
|
||||
}
|
11
testenv/testenv_cgo.go
Normal file
11
testenv/testenv_cgo.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build cgo
|
||||
|
||||
package testenv
|
||||
|
||||
func init() {
|
||||
haveCGO = true
|
||||
}
|
20
testenv/testenv_notwin.go
Normal file
20
testenv/testenv_notwin.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package testenv
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func hasSymlink() (ok bool, reason string) {
|
||||
switch runtime.GOOS {
|
||||
case "android", "nacl", "plan9":
|
||||
return false, ""
|
||||
}
|
||||
|
||||
return true, ""
|
||||
}
|
49
testenv/testenv_windows.go
Normal file
49
testenv/testenv_windows.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package testenv
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var symlinkOnce sync.Once
|
||||
var winSymlinkErr error
|
||||
|
||||
func initWinHasSymlink() {
|
||||
tmpdir, err := ioutil.TempDir("", "symtest")
|
||||
if err != nil {
|
||||
panic("failed to create temp directory: " + err.Error())
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
|
||||
if err != nil {
|
||||
err = err.(*os.LinkError).Err
|
||||
switch err {
|
||||
case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
|
||||
winSymlinkErr = err
|
||||
}
|
||||
}
|
||||
os.Remove("target")
|
||||
}
|
||||
|
||||
func hasSymlink() (ok bool, reason string) {
|
||||
symlinkOnce.Do(initWinHasSymlink)
|
||||
|
||||
switch winSymlinkErr {
|
||||
case nil:
|
||||
return true, ""
|
||||
case syscall.EWINDOWS:
|
||||
return false, ": symlinks are not supported on your version of Windows"
|
||||
case syscall.ERROR_PRIVILEGE_NOT_HELD:
|
||||
return false, ": you don't have enough privileges to create symlinks"
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
|
@ -9,7 +9,7 @@ import (
|
|||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"github.com/Jigsaw-Code/utls/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
|
|
121
u_common.go
Normal file
121
u_common.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package tls
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Naming convention:
|
||||
// Unsupported things are prefixed with "Fake"
|
||||
// Supported things, that have changed their ID are prefixed with "Old"
|
||||
// Supported but disabled things are prefixed with "Disabled". We will _enable_ them.
|
||||
const (
|
||||
// padding isn't quite a 'fake' extension, as uTLS provides full implementation
|
||||
// just denotes that crypto/tls doesn't provide it
|
||||
fakeExtensionPadding uint16 = 21
|
||||
|
||||
// extensions below break connection, if server echoes them back
|
||||
fakeExtensionExtendedMasterSecret uint16 = 23
|
||||
fakeExtensionChannelID uint16 = 30032 // not IANA assigned
|
||||
)
|
||||
|
||||
const (
|
||||
OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc13)
|
||||
OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc14)
|
||||
|
||||
FAKE_OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = uint16(0xcc15) // we can try to craft these ciphersuites
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = uint16(0x009e) // from existing pieces, if needed
|
||||
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA = uint16(0x0033)
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA = uint16(0x0039)
|
||||
FAKE_TLS_RSA_WITH_RC4_128_MD5 = uint16(0x0004)
|
||||
FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV = uint16(0x00ff)
|
||||
)
|
||||
|
||||
// newest signatures
|
||||
var (
|
||||
fakeRsaPssSha256 = SignatureAndHash{0x08, 0x04} // also declared in common.go as type SignatureScheme,
|
||||
fakeRsaPssSha384 = SignatureAndHash{0x08, 0x05} // but not used by default and not implemented
|
||||
fakeRsaPssSha512 = SignatureAndHash{0x08, 0x06}
|
||||
// fakeEd25519 = SignatureAndHash{0x08, 0x07}
|
||||
// fakeEd448 = SignatureAndHash{0x08, 0x08}
|
||||
)
|
||||
|
||||
// IDs of hash functions in signatures
|
||||
const (
|
||||
disabledHashSHA512 uint8 = 6 // Supported, but disabled by default. Will be enabled, as needed
|
||||
fakeHashSHA224 uint8 = 3 // Supported, but we won't enable it: sounds esoteric and fishy
|
||||
|
||||
)
|
||||
|
||||
type ClientHelloID struct {
|
||||
Browser string
|
||||
Version uint16
|
||||
// TODO: consider adding OS?
|
||||
}
|
||||
|
||||
func (p *ClientHelloID) Str() string {
|
||||
return fmt.Sprintf("%s-%d", p.Browser, p.Version)
|
||||
}
|
||||
|
||||
const (
|
||||
helloGolang = "Golang"
|
||||
helloRandomized = "Randomized"
|
||||
helloCustom = "Custom"
|
||||
helloFirefox = "Firefox"
|
||||
helloChrome = "Chrome"
|
||||
helloAndroid = "Android"
|
||||
)
|
||||
|
||||
const (
|
||||
helloAutoVers = iota
|
||||
helloRandomizedALPN
|
||||
helloRandomizedNoALPN
|
||||
)
|
||||
|
||||
var (
|
||||
// HelloGolang will use default "crypto/tls" handshake marshaling codepath, which WILL
|
||||
// overwrite your changes to Hello(Config, Session are fine).
|
||||
// You might want to call BuildHandshakeState() before applying any changes.
|
||||
// UConn.Extensions will be completely ignored.
|
||||
HelloGolang ClientHelloID = ClientHelloID{helloGolang, helloAutoVers}
|
||||
|
||||
// HelloCustom will prepare ClientHello with empty uconn.Extensions so you can fill it with TLSExtension's manually
|
||||
HelloCustom ClientHelloID = ClientHelloID{helloCustom, helloAutoVers}
|
||||
|
||||
// HelloRandomized* randomly adds/reorders extensions, ciphersuites, etc.
|
||||
HelloRandomized ClientHelloID = ClientHelloID{helloRandomized, helloAutoVers}
|
||||
HelloRandomizedALPN ClientHelloID = ClientHelloID{helloRandomized, helloRandomizedALPN}
|
||||
HelloRandomizedNoALPN ClientHelloID = ClientHelloID{helloRandomized, helloRandomizedNoALPN}
|
||||
|
||||
// The rest will will parrot given browser.
|
||||
HelloFirefox_Auto ClientHelloID = ClientHelloID{helloFirefox, helloAutoVers}
|
||||
HelloFirefox_53_WIP = ClientHelloID{helloFirefox, 53}
|
||||
|
||||
HelloChrome_Auto ClientHelloID = ClientHelloID{helloChrome, helloAutoVers}
|
||||
HelloChrome_58 ClientHelloID = ClientHelloID{helloChrome, 58}
|
||||
|
||||
HelloAndroid_Auto ClientHelloID = ClientHelloID{helloAndroid, helloAutoVers}
|
||||
HelloAndroid_6_0_Browser ClientHelloID = ClientHelloID{helloAndroid, 23}
|
||||
HelloAndroid_5_1_Browser ClientHelloID = ClientHelloID{helloAndroid, 22}
|
||||
)
|
||||
|
||||
// Appends newCipher to cipherSuites, if not there already
|
||||
// Used to add old cipher ids
|
||||
func appendToGlobalCipherSuites(newCipher *cipherSuite) {
|
||||
for _, c := range cipherSuites {
|
||||
if c.id == newCipher.id {
|
||||
return
|
||||
}
|
||||
}
|
||||
cipherSuites = append(cipherSuites, newCipher)
|
||||
}
|
||||
|
||||
// Appends {hash, sig} to supportedSignatureAlgorithms, if not there already
|
||||
// Used to enable already supported but disabled signatures
|
||||
func appendToGlobalSigAlgs(hash uint8, sig uint8) {
|
||||
s := signatureAndHash{hash, sig}
|
||||
for _, c := range supportedSignatureAlgorithms {
|
||||
if c.hash == s.hash && c.signature == s.signature {
|
||||
return
|
||||
}
|
||||
}
|
||||
supportedSignatureAlgorithms = append(supportedSignatureAlgorithms, s)
|
||||
}
|
373
u_conn.go
Normal file
373
u_conn.go
Normal file
|
@ -0,0 +1,373 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type UConn struct {
|
||||
*Conn
|
||||
|
||||
Extensions []TLSExtension
|
||||
clientHelloID ClientHelloID
|
||||
|
||||
HandshakeState ClientHandshakeState
|
||||
|
||||
HandshakeStateBuilt bool
|
||||
}
|
||||
|
||||
// UClient returns a new uTLS client, with behavior depending on clientHelloID.
|
||||
// Config CAN be nil, but make sure to eventually specify ServerName.
|
||||
func UClient(conn net.Conn, config *Config, clientHelloID ClientHelloID) *UConn {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
tlsConn := Conn{conn: conn, config: config, isClient: true}
|
||||
handshakeState := ClientHandshakeState{C: &tlsConn, Hello: &ClientHelloMsg{}}
|
||||
uconn := UConn{Conn: &tlsConn, clientHelloID: clientHelloID, HandshakeState: handshakeState}
|
||||
return &uconn
|
||||
}
|
||||
|
||||
// BuildHandshakeState() overwrites most fields, therefore, it is advised to manually call this function,
|
||||
// if you need to inspect/change contents after parroting/making default Golang ClientHello.
|
||||
// Otherwise, there is no need to call this function explicitly.
|
||||
func (uconn *UConn) BuildHandshakeState() error {
|
||||
if uconn.clientHelloID == HelloGolang {
|
||||
// use default Golang ClientHello.
|
||||
hello, err := makeClientHello(uconn.config)
|
||||
if uconn.HandshakeState.Session != nil {
|
||||
// session is lost at makeClientHello(), let's reapply
|
||||
uconn.SetSessionState(uconn.HandshakeState.Session)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uconn.HandshakeState.Hello = hello.getPublicPtr()
|
||||
} else {
|
||||
err := uconn.generateClientHelloConfig(uconn.clientHelloID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = uconn.applyConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = uconn.marshalClientHello()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
uconn.HandshakeStateBuilt = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// If you want you session tickets to be reused - use same cache on following connections
|
||||
func (uconn *UConn) SetSessionState(session *ClientSessionState) {
|
||||
uconn.HandshakeState.Session = session
|
||||
if session != nil {
|
||||
uconn.HandshakeState.Hello.SessionTicket = session.sessionTicket
|
||||
}
|
||||
uconn.HandshakeState.Hello.TicketSupported = true
|
||||
for _, ext := range uconn.Extensions {
|
||||
st, ok := ext.(*SessionTicketExtension)
|
||||
if ok {
|
||||
st.Session = session
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If you want you session tickets to be reused - use same cache on following connections
|
||||
func (uconn *UConn) SetSessionCache(cache ClientSessionCache) {
|
||||
uconn.config.ClientSessionCache = cache
|
||||
uconn.HandshakeState.Hello.TicketSupported = true
|
||||
}
|
||||
|
||||
// r has to be 32 bytes long
|
||||
func (uconn *UConn) SetClientRandom(r []byte) error {
|
||||
if len(r) != 32 {
|
||||
return errors.New("Incorrect client random length! Expected: 32, got: " + strconv.Itoa(len(r)))
|
||||
} else {
|
||||
uconn.HandshakeState.Hello.Random = make([]byte, 32)
|
||||
copy(uconn.HandshakeState.Hello.Random, r)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (uconn *UConn) SetSNI(sni string) {
|
||||
hname := hostnameInSNI(sni)
|
||||
uconn.config.ServerName = hname
|
||||
for _, ext := range uconn.Extensions {
|
||||
sniExt, ok := ext.(*SNIExtension)
|
||||
if ok {
|
||||
sniExt.ServerName = hname
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handshake runs the client handshake using given clientHandshakeState
|
||||
// Requires hs.hello, and, optionally, hs.session to be set.
|
||||
func (c *UConn) Handshake() error {
|
||||
// This code was copied almost as is from tls/conn.go
|
||||
// c.handshakeErr and c.handshakeComplete are protected by
|
||||
// c.handshakeMutex. In order to perform a handshake, we need to lock
|
||||
// c.in also and c.handshakeMutex must be locked after c.in.
|
||||
//
|
||||
// However, if a Read() operation is hanging then it'll be holding the
|
||||
// lock on c.in and so taking it here would cause all operations that
|
||||
// need to check whether a handshake is pending (such as Write) to
|
||||
// block.
|
||||
//
|
||||
// Thus we first take c.handshakeMutex to check whether a handshake is
|
||||
// needed.
|
||||
//
|
||||
// If so then, previously, this code would unlock handshakeMutex and
|
||||
// then lock c.in and handshakeMutex in the correct order to run the
|
||||
// handshake. The problem was that it was possible for a Read to
|
||||
// complete the handshake once handshakeMutex was unlocked and then
|
||||
// keep c.in while waiting for network data. Thus a concurrent
|
||||
// operation could be blocked on c.in.
|
||||
//
|
||||
// Thus handshakeCond is used to signal that a goroutine is committed
|
||||
// to running the handshake and other goroutines can wait on it if they
|
||||
// need. handshakeCond is protected by handshakeMutex.
|
||||
c.handshakeMutex.Lock()
|
||||
defer c.handshakeMutex.Unlock()
|
||||
|
||||
for {
|
||||
if err := c.handshakeErr; err != nil {
|
||||
return err
|
||||
}
|
||||
if c.handshakeComplete {
|
||||
return nil
|
||||
}
|
||||
if c.handshakeCond == nil {
|
||||
break
|
||||
}
|
||||
|
||||
c.handshakeCond.Wait()
|
||||
}
|
||||
|
||||
// Set handshakeCond to indicate that this goroutine is committing to
|
||||
// running the handshake.
|
||||
c.handshakeCond = sync.NewCond(&c.handshakeMutex)
|
||||
c.handshakeMutex.Unlock()
|
||||
|
||||
c.in.Lock()
|
||||
defer c.in.Unlock()
|
||||
|
||||
c.handshakeMutex.Lock()
|
||||
|
||||
// The handshake cannot have completed when handshakeMutex was unlocked
|
||||
// because this goroutine set handshakeCond.
|
||||
if c.handshakeErr != nil || c.handshakeComplete {
|
||||
panic("handshake should not have been able to complete after handshakeCond was set")
|
||||
}
|
||||
|
||||
if !c.isClient {
|
||||
panic("Servers should not call ClientHandshakeWithState()")
|
||||
}
|
||||
|
||||
if !c.HandshakeStateBuilt {
|
||||
err := c.BuildHandshakeState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
privateState := c.HandshakeState.getPrivatePtr()
|
||||
c.handshakeErr = c.clientHandshakeWithState(privateState)
|
||||
c.HandshakeState = *privateState.getPublicPtr()
|
||||
|
||||
if c.handshakeErr == nil {
|
||||
c.handshakes++
|
||||
} else {
|
||||
// If an error occurred during the hadshake try to flush the
|
||||
// alert that might be left in the buffer.
|
||||
c.flush()
|
||||
}
|
||||
|
||||
if c.handshakeErr == nil && !c.handshakeComplete {
|
||||
panic("handshake should have had a result.")
|
||||
}
|
||||
|
||||
// Wake any other goroutines that are waiting for this handshake to complete.
|
||||
c.handshakeCond.Broadcast()
|
||||
c.handshakeCond = nil
|
||||
|
||||
return c.handshakeErr
|
||||
}
|
||||
|
||||
// c.out.Mutex <= L; c.handshakeMutex <= L.
|
||||
func (c *UConn) clientHandshakeWithState(hs *clientHandshakeState) error {
|
||||
// This code was copied almost as is from tls/handshake_client.go
|
||||
if c.config == nil {
|
||||
c.config = &Config{}
|
||||
}
|
||||
|
||||
// This may be a renegotiation handshake, in which case some fields
|
||||
// need to be reset.
|
||||
c.didResume = false
|
||||
|
||||
if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
|
||||
return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
|
||||
}
|
||||
|
||||
nextProtosLength := 0
|
||||
for _, proto := range c.config.NextProtos {
|
||||
if l := len(proto); l == 0 || l > 255 {
|
||||
return errors.New("tls: invalid NextProtos value")
|
||||
} else {
|
||||
nextProtosLength += 1 + l
|
||||
}
|
||||
}
|
||||
if nextProtosLength > 0xffff {
|
||||
return errors.New("tls: NextProtos values too large")
|
||||
}
|
||||
|
||||
var session *ClientSessionState
|
||||
sessionCache := c.config.ClientSessionCache
|
||||
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||||
|
||||
// If sessionCache is set but session itself isn't - try to retrieve session from cache
|
||||
if sessionCache != nil && hs.session != nil {
|
||||
hs.hello.ticketSupported = true
|
||||
// Session resumption is not allowed if renegotiating because
|
||||
// renegotiation is primarily used to allow a client to send a client
|
||||
// certificate, which would be skipped if session resumption occurred.
|
||||
if c.handshakes == 0 {
|
||||
// Try to resume a previously negotiated TLS session, if
|
||||
// available.
|
||||
candidateSession, ok := sessionCache.Get(cacheKey)
|
||||
if ok {
|
||||
// Check that the ciphersuite/version used for the
|
||||
// previous session are still valid.
|
||||
cipherSuiteOk := false
|
||||
for _, id := range hs.hello.cipherSuites {
|
||||
if id == candidateSession.cipherSuite {
|
||||
cipherSuiteOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
versOk := candidateSession.vers >= c.config.minVersion() &&
|
||||
candidateSession.vers <= c.config.maxVersion()
|
||||
if versOk && cipherSuiteOk {
|
||||
session = candidateSession
|
||||
}
|
||||
if session != nil {
|
||||
hs.hello.sessionTicket = session.sessionTicket
|
||||
// A random session ID is used to detect when the
|
||||
// server accepted the ticket and is resuming a session
|
||||
// (see RFC 5077).
|
||||
hs.hello.sessionId = make([]byte, 16)
|
||||
if _, err := io.ReadFull(c.config.rand(), hs.hello.sessionId); err != nil {
|
||||
return errors.New("tls: short read from Rand: " + err.Error())
|
||||
}
|
||||
}
|
||||
hs.session = session
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := hs.handshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
// If we had a successful handshake and hs.session is different from the one already cached - cache a new one
|
||||
if sessionCache != nil && hs.session != nil && hs.session != session {
|
||||
sessionCache.Put(cacheKey, hs.session)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uconn *UConn) applyConfig() error {
|
||||
for _, ext := range uconn.Extensions {
|
||||
err := ext.writeToUConn(uconn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uconn *UConn) marshalClientHello() error {
|
||||
hello := uconn.HandshakeState.Hello
|
||||
headerLength := 2 + 32 + 1 + len(hello.SessionId) +
|
||||
2 + len(hello.CipherSuites)*2 +
|
||||
1 + len(hello.CompressionMethods)
|
||||
|
||||
extensionsLen := 0
|
||||
var paddingExt *FakePaddingExtension
|
||||
for _, ext := range uconn.Extensions {
|
||||
if pe, ok := ext.(*FakePaddingExtension); !ok {
|
||||
// If not padding - just add length of extension to total length
|
||||
extensionsLen += ext.Len()
|
||||
} else {
|
||||
// If padding - process it later
|
||||
if paddingExt == nil {
|
||||
paddingExt = pe
|
||||
} else {
|
||||
return errors.New("Multiple padding extensions!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if paddingExt != nil {
|
||||
// determine padding extension presence and length
|
||||
paddingExt.Update(headerLength + 4 + extensionsLen + 2)
|
||||
extensionsLen += paddingExt.Len()
|
||||
}
|
||||
|
||||
helloLen := headerLength
|
||||
if len(uconn.Extensions) > 0 {
|
||||
helloLen += 2 + extensionsLen // 2 bytes for extensions' length
|
||||
}
|
||||
|
||||
helloBuffer := bytes.Buffer{}
|
||||
bufferedWriter := bufio.NewWriterSize(&helloBuffer, helloLen+4) // 1 byte for tls record type, 3 for length
|
||||
// We use buffered Writer to avoid checking write errors after every Write(): whenever first error happens
|
||||
// Write() will become noop, and error will be accessible via Flush(), which is called once in the end
|
||||
|
||||
binary.Write(bufferedWriter, binary.BigEndian, typeClientHello)
|
||||
helloLenBytes := []byte{byte(helloLen >> 16), byte(helloLen >> 8), byte(helloLen)} // poor man's uint24
|
||||
binary.Write(bufferedWriter, binary.BigEndian, helloLenBytes)
|
||||
binary.Write(bufferedWriter, binary.BigEndian, hello.Vers)
|
||||
|
||||
binary.Write(bufferedWriter, binary.BigEndian, hello.Random)
|
||||
|
||||
binary.Write(bufferedWriter, binary.BigEndian, uint8(len(hello.SessionId)))
|
||||
binary.Write(bufferedWriter, binary.BigEndian, hello.SessionId)
|
||||
|
||||
binary.Write(bufferedWriter, binary.BigEndian, uint16(len(hello.CipherSuites)<<1))
|
||||
for _, suite := range hello.CipherSuites {
|
||||
binary.Write(bufferedWriter, binary.BigEndian, suite)
|
||||
}
|
||||
|
||||
binary.Write(bufferedWriter, binary.BigEndian, uint8(len(hello.CompressionMethods)))
|
||||
binary.Write(bufferedWriter, binary.BigEndian, hello.CompressionMethods)
|
||||
|
||||
if len(uconn.Extensions) > 0 {
|
||||
binary.Write(bufferedWriter, binary.BigEndian, uint16(extensionsLen))
|
||||
for _, ext := range uconn.Extensions {
|
||||
bufferedWriter.ReadFrom(ext)
|
||||
}
|
||||
}
|
||||
|
||||
if helloBuffer.Len() != 4+helloLen {
|
||||
return errors.New("utls: unexpected ClientHello length. Expected: " + strconv.Itoa(4+helloLen) +
|
||||
". Got: " + strconv.Itoa(helloBuffer.Len()))
|
||||
}
|
||||
|
||||
err := bufferedWriter.Flush()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hello.Raw = helloBuffer.Bytes()
|
||||
return nil
|
||||
}
|
447
u_conn_test.go
Normal file
447
u_conn_test.go
Normal file
|
@ -0,0 +1,447 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
TODO:
|
||||
Reuse examples in tests?
|
||||
Add tests for randomized and no parrot
|
||||
Add session ticket tests
|
||||
Add set client random tests
|
||||
*/
|
||||
|
||||
func TestUTLSMarshalNoOp(t *testing.T) {
|
||||
// we rely on
|
||||
str := "We rely on clientHelloMsg.marshal() not doing anything if clientHelloMsg.raw is set"
|
||||
cHello, err := makeClientHello(getUTLSTestConfig())
|
||||
if err != nil {
|
||||
t.Errorf("Got error: %s; expected to succeed", err)
|
||||
}
|
||||
cHello.raw = []byte(str)
|
||||
marshalledHello := cHello.marshal()
|
||||
if strings.Compare(string(marshalledHello), str) != 0 {
|
||||
t.Errorf("clientHelloMsg.marshal() is not NOOP! Expected to get: %s, got: %s", str, string(marshalledHello))
|
||||
}
|
||||
}
|
||||
|
||||
func runUTLSClientTestForVersion(t *testing.T, template *clientTest, prefix, option string, helloID ClientHelloID) {
|
||||
test := *template
|
||||
test.name = prefix + test.name
|
||||
if len(test.command) == 0 {
|
||||
test.command = defaultClientCommand
|
||||
}
|
||||
test.command = append([]string(nil), test.command...)
|
||||
test.command = append(test.command, option)
|
||||
test.runUTLS(t, *update, helloID)
|
||||
}
|
||||
|
||||
func runUTLSClientTestTLS12(t *testing.T, template *clientTest, helloID ClientHelloID) {
|
||||
runUTLSClientTestForVersion(t, template, "TLSv12-", "-tls1_2", helloID)
|
||||
}
|
||||
|
||||
func (test *clientTest) runUTLS(t *testing.T, write bool, helloID ClientHelloID) {
|
||||
checkOpenSSLVersion(t)
|
||||
|
||||
var clientConn, serverConn net.Conn
|
||||
var recordingConn *recordingConn
|
||||
var childProcess *exec.Cmd
|
||||
var stdin opensslInput
|
||||
var stdout *opensslOutputSink
|
||||
|
||||
if write {
|
||||
var err error
|
||||
recordingConn, childProcess, stdin, stdout, err = test.connFromCommand()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to start subcommand: %s", err)
|
||||
}
|
||||
clientConn = recordingConn
|
||||
} else {
|
||||
clientConn, serverConn = net.Pipe()
|
||||
}
|
||||
|
||||
config := test.config
|
||||
if config == nil {
|
||||
t.Error("Explicit config is mandatory")
|
||||
return
|
||||
}
|
||||
client := UClient(clientConn, config, helloID)
|
||||
|
||||
doneChan := make(chan bool)
|
||||
go func() {
|
||||
defer func() { doneChan <- true }()
|
||||
defer clientConn.Close()
|
||||
defer client.Close()
|
||||
|
||||
err := client.Handshake()
|
||||
if err != nil {
|
||||
t.Errorf("Client.Handshake() failed: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := client.Write([]byte("hello\n")); err != nil {
|
||||
t.Errorf("Client.Write failed: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
for i := 1; i <= test.numRenegotiations; i++ {
|
||||
// The initial handshake will generate a
|
||||
// handshakeComplete signal which needs to be quashed.
|
||||
if i == 1 && write {
|
||||
<-stdout.handshakeComplete
|
||||
}
|
||||
|
||||
// OpenSSL will try to interleave application data and
|
||||
// a renegotiation if we send both concurrently.
|
||||
// Therefore: ask OpensSSL to start a renegotiation, run
|
||||
// a goroutine to call client.Read and thus process the
|
||||
// renegotiation request, watch for OpenSSL's stdout to
|
||||
// indicate that the handshake is complete and,
|
||||
// finally, have OpenSSL write something to cause
|
||||
// client.Read to complete.
|
||||
if write {
|
||||
stdin <- opensslRenegotiate
|
||||
}
|
||||
|
||||
signalChan := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer func() { signalChan <- struct{}{} }()
|
||||
|
||||
buf := make([]byte, 256)
|
||||
n, err := client.Read(buf)
|
||||
|
||||
if test.checkRenegotiationError != nil {
|
||||
newErr := test.checkRenegotiationError(i, err)
|
||||
if err != nil && newErr == nil {
|
||||
return
|
||||
}
|
||||
err = newErr
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Client.Read failed after renegotiation #%d: %s", i, err)
|
||||
return
|
||||
}
|
||||
|
||||
buf = buf[:n]
|
||||
if !bytes.Equal([]byte(opensslSentinel), buf) {
|
||||
t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
|
||||
}
|
||||
|
||||
if expected := i + 1; client.handshakes != expected {
|
||||
t.Errorf("client should have recorded %d handshakes, but believes that %d have occurred", expected, client.handshakes)
|
||||
}
|
||||
}()
|
||||
|
||||
if write && test.renegotiationExpectedToFail != i {
|
||||
<-stdout.handshakeComplete
|
||||
stdin <- opensslSendSentinel
|
||||
}
|
||||
<-signalChan
|
||||
}
|
||||
|
||||
if test.validate != nil {
|
||||
if err := test.validate(client.ConnectionState()); err != nil {
|
||||
t.Errorf("validate callback returned error: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if !write {
|
||||
flows, err := test.loadData()
|
||||
if err != nil {
|
||||
t.Fatalf("%s: failed to load data from %s: %v", test.name, test.dataPath(), err)
|
||||
}
|
||||
for i, b := range flows {
|
||||
if i%2 == 1 {
|
||||
serverConn.Write(b)
|
||||
continue
|
||||
}
|
||||
bb := make([]byte, len(b))
|
||||
_, err := io.ReadFull(serverConn, bb)
|
||||
if err != nil {
|
||||
t.Fatalf("%s #%d: %s", test.name, i, err)
|
||||
}
|
||||
if !bytes.Equal(b, bb) {
|
||||
t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i, bb, b)
|
||||
}
|
||||
}
|
||||
serverConn.Close()
|
||||
}
|
||||
|
||||
<-doneChan
|
||||
|
||||
if write {
|
||||
path := test.dataPath()
|
||||
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create output file: %s", err)
|
||||
}
|
||||
defer out.Close()
|
||||
recordingConn.Close()
|
||||
close(stdin)
|
||||
childProcess.Process.Kill()
|
||||
childProcess.Wait()
|
||||
if len(recordingConn.flows) < 3 {
|
||||
os.Stdout.Write(childProcess.Stdout.(*opensslOutputSink).all)
|
||||
t.Fatalf("Client connection didn't work")
|
||||
}
|
||||
recordingConn.WriteTo(out)
|
||||
fmt.Printf("Wrote %s\n", path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUTLSHandshakeClientParrotAndroid_5_1(t *testing.T) {
|
||||
helloID := HelloAndroid_5_1_Browser
|
||||
|
||||
// As this package sometimes has to modify global vars cipherSuites and supportedSignatureAlgorithms,
|
||||
// we'll back them up and restore after running the tests.
|
||||
cipherSuitesBackup := make([]*cipherSuite, len(cipherSuites))
|
||||
supportedSignatureAlgorithmsBackup := make([]signatureAndHash, len(supportedSignatureAlgorithms))
|
||||
copy(cipherSuitesBackup, cipherSuites)
|
||||
copy(supportedSignatureAlgorithmsBackup, supportedSignatureAlgorithms)
|
||||
defer func() {
|
||||
cipherSuites = cipherSuitesBackup
|
||||
supportedSignatureAlgorithms = supportedSignatureAlgorithmsBackup
|
||||
}()
|
||||
|
||||
// Android 5.1 offers old cipher ids for these, but current versions of OpenSSL no longer recognize old ids
|
||||
// testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
|
||||
// testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
|
||||
|
||||
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, helloID)
|
||||
|
||||
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, helloID)
|
||||
}
|
||||
|
||||
// Enable whenever EMS is implemented
|
||||
func disabledtestUTLSHandshakeClientParrotAndroid_6_0(t *testing.T) {
|
||||
helloID := HelloAndroid_6_0_Browser
|
||||
|
||||
// As this package sometimes has to modify global vars cipherSuites and supportedSignatureAlgorithms,
|
||||
// we'll back them up and restore after running the tests.
|
||||
cipherSuitesBackup := make([]*cipherSuite, len(cipherSuites))
|
||||
supportedSignatureAlgorithmsBackup := make([]signatureAndHash, len(supportedSignatureAlgorithms))
|
||||
copy(cipherSuitesBackup, cipherSuites)
|
||||
copy(supportedSignatureAlgorithmsBackup, supportedSignatureAlgorithms)
|
||||
defer func() {
|
||||
cipherSuites = cipherSuitesBackup
|
||||
supportedSignatureAlgorithms = supportedSignatureAlgorithmsBackup
|
||||
}()
|
||||
|
||||
// Android 6.0 offers old cipher ids for these, but current versions of OpenSSL no longer recognize old ids
|
||||
// testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
|
||||
// testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
|
||||
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
|
||||
|
||||
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, helloID)
|
||||
}
|
||||
|
||||
// Enable whenever EMS is implemented
|
||||
func disabledtestUTLSHandshakeClientParrotChrome_58(t *testing.T) {
|
||||
helloID := HelloChrome_58
|
||||
|
||||
// As this package sometimes has to modify global vars cipherSuites and supportedSignatureAlgorithms,
|
||||
// we'll back them up and restore after running the tests.
|
||||
cipherSuitesBackup := make([]*cipherSuite, len(cipherSuites))
|
||||
supportedSignatureAlgorithmsBackup := make([]signatureAndHash, len(supportedSignatureAlgorithms))
|
||||
copy(cipherSuitesBackup, cipherSuites)
|
||||
copy(supportedSignatureAlgorithmsBackup, supportedSignatureAlgorithms)
|
||||
defer func() {
|
||||
cipherSuites = cipherSuitesBackup
|
||||
supportedSignatureAlgorithms = supportedSignatureAlgorithmsBackup
|
||||
}()
|
||||
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, helloID)
|
||||
|
||||
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, helloID)
|
||||
|
||||
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, helloID)
|
||||
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, helloID)
|
||||
|
||||
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, helloID)
|
||||
}
|
||||
|
||||
func getUTLSTestConfig() *Config {
|
||||
testUTLSConfig := &Config{
|
||||
Time: func() time.Time { return time.Unix(0, 0) },
|
||||
Rand: zeroSource{},
|
||||
InsecureSkipVerify: true,
|
||||
MinVersion: VersionSSL30,
|
||||
MaxVersion: VersionTLS12,
|
||||
CipherSuites: allCipherSuites(),
|
||||
}
|
||||
return testUTLSConfig
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
opensslCipherName := "ECDHE-RSA-AES128-SHA"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
opensslCipherName := "ECDHE-RSA-AES256-SHA"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
opensslCipherName := "ECDHE-ECDSA-AES128-SHA"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
cert: testECDSACertificate,
|
||||
key: testECDSAPrivateKey,
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
opensslCipherName := "ECDHE-ECDSA-AES256-SHA"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
cert: testECDSACertificate,
|
||||
key: testECDSAPrivateKey,
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
opensslCipherName := "AES128-GCM-SHA256"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
|
||||
opensslCipherName := "ECDHE-ECDSA-AES128-GCM-SHA256"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
cert: testECDSACertificate,
|
||||
key: testECDSAPrivateKey,
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
|
||||
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
opensslCipherName := "ECDHE-ECDSA-AES256-GCM-SHA256"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
cert: testECDSACertificate,
|
||||
key: testECDSAPrivateKey,
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
|
||||
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}
|
||||
opensslCipherName := "ECDHE-RSA-CHACHA20-POLY1305"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
config: config,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
||||
|
||||
func testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t *testing.T, helloID ClientHelloID) {
|
||||
config := getUTLSTestConfig()
|
||||
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}
|
||||
opensslCipherName := "ECDHE-ECDSA-CHACHA20-POLY1305"
|
||||
test := &clientTest{
|
||||
name: "UTLS-" + opensslCipherName + "-" + helloID.Str(),
|
||||
command: []string{"openssl", "s_server", "-cipher", opensslCipherName},
|
||||
config: config,
|
||||
cert: testECDSACertificate,
|
||||
key: testECDSAPrivateKey,
|
||||
}
|
||||
|
||||
runUTLSClientTestTLS12(t, test, helloID)
|
||||
}
|
644
u_parrots.go
Normal file
644
u_parrots.go
Normal file
|
@ -0,0 +1,644 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (uconn *UConn) generateClientHelloConfig(id ClientHelloID) error {
|
||||
uconn.clientHelloID = id
|
||||
switch uconn.clientHelloID {
|
||||
case HelloFirefox_53_WIP:
|
||||
return uconn.parrotFirefox_53_WIP()
|
||||
|
||||
case HelloAndroid_6_0_Browser:
|
||||
return uconn.parrotAndroid_6_0()
|
||||
case HelloAndroid_5_1_Browser:
|
||||
return uconn.parrotAndroid_5_1()
|
||||
|
||||
case HelloChrome_58:
|
||||
return uconn.parrotChrome_58()
|
||||
|
||||
case HelloRandomizedALPN:
|
||||
return uconn.parrotRandomizedALPN()
|
||||
case HelloRandomizedNoALPN:
|
||||
return uconn.parrotRandomizedNoALPN()
|
||||
|
||||
case HelloCustom:
|
||||
return uconn.parrotCustom()
|
||||
|
||||
// following ClientHello's are aliases, so we call generateClientHelloConfig() again to set the correct id
|
||||
case HelloRandomized:
|
||||
if tossBiasedCoin(0.5) {
|
||||
return uconn.generateClientHelloConfig(HelloRandomizedALPN)
|
||||
} else {
|
||||
return uconn.generateClientHelloConfig(HelloRandomizedNoALPN)
|
||||
}
|
||||
case HelloAndroid_Auto:
|
||||
return uconn.generateClientHelloConfig(HelloAndroid_6_0_Browser)
|
||||
case HelloFirefox_Auto:
|
||||
return uconn.generateClientHelloConfig(HelloFirefox_53_WIP)
|
||||
case HelloChrome_Auto:
|
||||
return uconn.generateClientHelloConfig(HelloChrome_58)
|
||||
|
||||
default:
|
||||
return errors.New("Unknown ParrotID: " + id.Str())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fills clientHello header(everything but extensions) fields, which are not set explicitly yet, with defaults
|
||||
func (uconn *UConn) fillClientHelloHeader() error {
|
||||
hello := uconn.HandshakeState.Hello
|
||||
if hello.Vers == 0 {
|
||||
hello.Vers = VersionTLS12
|
||||
}
|
||||
switch len(hello.Random) {
|
||||
case 0:
|
||||
hello.Random = make([]byte, 32)
|
||||
_, err := io.ReadFull(uconn.config.rand(), hello.Random)
|
||||
if err != nil {
|
||||
return errors.New("tls: short read from Rand: " + err.Error())
|
||||
}
|
||||
case 32:
|
||||
// carry on
|
||||
default:
|
||||
return errors.New("ClientHello expected length: 32 bytes. Got: " +
|
||||
strconv.Itoa(len(hello.Random)) + " bytes")
|
||||
}
|
||||
if len(hello.CipherSuites) == 0 {
|
||||
hello.CipherSuites = defaultCipherSuites()
|
||||
}
|
||||
if len(hello.CompressionMethods) == 0 {
|
||||
hello.CompressionMethods = []uint8{compressionNone}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uconn *UConn) parrotFirefox_53_WIP() error {
|
||||
/*
|
||||
Work in progress!
|
||||
TODO: double check session id generation
|
||||
TODO: add firefox-style padding
|
||||
*/
|
||||
hello := uconn.HandshakeState.Hello
|
||||
session := uconn.HandshakeState.Session
|
||||
hello.CipherSuites = []uint16{
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
}
|
||||
err := uconn.fillClientHelloHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sni := SNIExtension{uconn.config.ServerName}
|
||||
ems := FakeExtendedMasterSecretExtension{}
|
||||
reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
|
||||
curves := SupportedCurvesExtension{[]CurveID{X25519, CurveP256, CurveP384, CurveP521}}
|
||||
points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
|
||||
sessionTicket := SessionTicketExtension{Session: session}
|
||||
if session != nil {
|
||||
sessionTicket.Session = session
|
||||
if len(session.SessionTicket()) > 0 {
|
||||
hello.SessionId = make([]byte, 32)
|
||||
_, err := io.ReadFull(uconn.config.rand(), hello.SessionId)
|
||||
if err != nil {
|
||||
return errors.New("tls: short read from Rand: " + err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
alpn := ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}
|
||||
status := StatusRequestExtension{}
|
||||
sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
|
||||
{hashSHA256, signatureECDSA},
|
||||
{hashSHA384, signatureECDSA},
|
||||
{disabledHashSHA512, signatureECDSA},
|
||||
fakeRsaPssSha256,
|
||||
fakeRsaPssSha384,
|
||||
fakeRsaPssSha512,
|
||||
{hashSHA256, signatureRSA},
|
||||
{hashSHA384, signatureRSA},
|
||||
{disabledHashSHA512, signatureRSA},
|
||||
{hashSHA1, signatureECDSA},
|
||||
{hashSHA1, signatureRSA}},
|
||||
}
|
||||
uconn.Extensions = []TLSExtension{
|
||||
&sni,
|
||||
&ems,
|
||||
&reneg,
|
||||
&curves,
|
||||
&points,
|
||||
&sessionTicket,
|
||||
&alpn,
|
||||
&status,
|
||||
&sigAndHash,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uconn *UConn) parrotAndroid_6_0() error {
|
||||
hello := uconn.HandshakeState.Hello
|
||||
session := uconn.HandshakeState.Session
|
||||
|
||||
appendToGlobalCipherSuites(&cipherSuite{OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12,
|
||||
ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305})
|
||||
appendToGlobalCipherSuites(&cipherSuite{OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12,
|
||||
ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadChaCha20Poly1305})
|
||||
hello.CipherSuites = []uint16{
|
||||
OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
FAKE_OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
||||
}
|
||||
err := uconn.fillClientHelloHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sni := SNIExtension{uconn.config.ServerName}
|
||||
ems := FakeExtendedMasterSecretExtension{}
|
||||
sessionTicket := SessionTicketExtension{Session: session}
|
||||
if session != nil {
|
||||
sessionTicket.Session = session
|
||||
if len(session.SessionTicket()) > 0 {
|
||||
sessionId := sha256.Sum256(session.SessionTicket())
|
||||
hello.SessionId = sessionId[:]
|
||||
}
|
||||
}
|
||||
appendToGlobalSigAlgs(disabledHashSHA512, signatureRSA)
|
||||
appendToGlobalSigAlgs(disabledHashSHA512, signatureECDSA)
|
||||
sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
|
||||
{disabledHashSHA512, signatureRSA},
|
||||
{disabledHashSHA512, signatureECDSA},
|
||||
{hashSHA384, signatureRSA},
|
||||
{hashSHA384, signatureECDSA},
|
||||
{hashSHA256, signatureRSA},
|
||||
{hashSHA256, signatureECDSA},
|
||||
{fakeHashSHA224, signatureRSA},
|
||||
{fakeHashSHA224, signatureECDSA},
|
||||
{hashSHA1, signatureRSA},
|
||||
{hashSHA1, signatureECDSA}},
|
||||
}
|
||||
status := StatusRequestExtension{}
|
||||
npn := NPNExtension{}
|
||||
sct := SCTExtension{}
|
||||
alpn := ALPNExtension{AlpnProtocols: []string{"http/1.1", "spdy/8.1"}}
|
||||
points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
|
||||
curves := SupportedCurvesExtension{[]CurveID{CurveP256, CurveP384}}
|
||||
padding := FakePaddingExtension{GetPaddingLen: boringPaddingStyle}
|
||||
|
||||
uconn.Extensions = []TLSExtension{
|
||||
&sni,
|
||||
&ems,
|
||||
&sessionTicket,
|
||||
&sigAndHash,
|
||||
&status,
|
||||
&npn,
|
||||
&sct,
|
||||
&alpn,
|
||||
&points,
|
||||
&curves,
|
||||
&padding,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (uconn *UConn) parrotAndroid_5_1() error {
|
||||
hello := uconn.HandshakeState.Hello
|
||||
session := uconn.HandshakeState.Session
|
||||
|
||||
appendToGlobalCipherSuites(&cipherSuite{OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12,
|
||||
ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305})
|
||||
appendToGlobalCipherSuites(&cipherSuite{OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, 12,
|
||||
ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadChaCha20Poly1305})
|
||||
hello.CipherSuites = []uint16{
|
||||
OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
FAKE_OLD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
FAKE_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_RSA_WITH_RC4_128_SHA,
|
||||
FAKE_TLS_RSA_WITH_RC4_128_MD5,
|
||||
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
FAKE_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
||||
}
|
||||
err := uconn.fillClientHelloHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sni := SNIExtension{uconn.config.ServerName}
|
||||
sessionTicket := SessionTicketExtension{Session: session}
|
||||
if session != nil {
|
||||
sessionTicket.Session = session
|
||||
if len(session.SessionTicket()) > 0 {
|
||||
sessionId := sha256.Sum256(session.SessionTicket())
|
||||
hello.SessionId = sessionId[:]
|
||||
}
|
||||
}
|
||||
appendToGlobalSigAlgs(disabledHashSHA512, signatureRSA)
|
||||
appendToGlobalSigAlgs(disabledHashSHA512, signatureECDSA)
|
||||
sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
|
||||
{disabledHashSHA512, signatureRSA},
|
||||
{disabledHashSHA512, signatureECDSA},
|
||||
{hashSHA384, signatureRSA},
|
||||
{hashSHA384, signatureECDSA},
|
||||
{hashSHA256, signatureRSA},
|
||||
{hashSHA256, signatureECDSA},
|
||||
{fakeHashSHA224, signatureRSA},
|
||||
{fakeHashSHA224, signatureECDSA},
|
||||
{hashSHA1, signatureRSA},
|
||||
{hashSHA1, signatureECDSA}},
|
||||
}
|
||||
status := StatusRequestExtension{}
|
||||
npn := NPNExtension{}
|
||||
sct := SCTExtension{}
|
||||
alpn := ALPNExtension{AlpnProtocols: []string{"http/1.1", "spdy/3", "spdy/3.1"}}
|
||||
points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
|
||||
curves := SupportedCurvesExtension{[]CurveID{CurveP256, CurveP384, CurveP521}}
|
||||
padding := FakePaddingExtension{GetPaddingLen: boringPaddingStyle}
|
||||
|
||||
uconn.Extensions = []TLSExtension{
|
||||
&sni,
|
||||
&sessionTicket,
|
||||
&sigAndHash,
|
||||
&status,
|
||||
&npn,
|
||||
&sct,
|
||||
&alpn,
|
||||
&points,
|
||||
&curves,
|
||||
&padding,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uconn *UConn) parrotChrome_58() error {
|
||||
hello := uconn.HandshakeState.Hello
|
||||
session := uconn.HandshakeState.Session
|
||||
|
||||
hello.CipherSuites = []uint16{
|
||||
GetBoringGREASEValue(hello.Random, ssl_grease_cipher),
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
}
|
||||
err := uconn.fillClientHelloHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
grease_ext1 := GetBoringGREASEValue(hello.Random, ssl_grease_extension1)
|
||||
grease_ext2 := GetBoringGREASEValue(hello.Random, ssl_grease_extension2)
|
||||
if grease_ext1 == grease_ext2 {
|
||||
grease_ext2 ^= 0x1010
|
||||
}
|
||||
|
||||
grease1 := FakeGREASEExtension{Value: grease_ext1}
|
||||
reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
|
||||
sni := SNIExtension{uconn.config.ServerName}
|
||||
ems := FakeExtendedMasterSecretExtension{}
|
||||
sessionTicket := SessionTicketExtension{Session: session}
|
||||
if session != nil {
|
||||
sessionTicket.Session = session
|
||||
if len(session.SessionTicket()) > 0 {
|
||||
sessionId := sha256.Sum256(session.SessionTicket())
|
||||
hello.SessionId = sessionId[:]
|
||||
}
|
||||
}
|
||||
sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: []SignatureAndHash{
|
||||
{hashSHA256, signatureECDSA},
|
||||
fakeRsaPssSha256,
|
||||
{hashSHA256, signatureRSA},
|
||||
{hashSHA384, signatureECDSA},
|
||||
fakeRsaPssSha384,
|
||||
{hashSHA384, signatureRSA},
|
||||
fakeRsaPssSha512,
|
||||
{disabledHashSHA512, signatureRSA},
|
||||
{hashSHA1, signatureRSA}},
|
||||
}
|
||||
status := StatusRequestExtension{}
|
||||
sct := SCTExtension{}
|
||||
alpn := ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}}
|
||||
channelId := FakeChannelIDExtension{}
|
||||
points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
|
||||
curves := SupportedCurvesExtension{[]CurveID{CurveID(GetBoringGREASEValue(hello.Random, ssl_grease_group)),
|
||||
X25519, CurveP256, CurveP384}}
|
||||
grease2 := FakeGREASEExtension{Value: grease_ext2, Body: []byte{0}}
|
||||
padding := FakePaddingExtension{GetPaddingLen: boringPaddingStyle}
|
||||
|
||||
uconn.Extensions = []TLSExtension{
|
||||
&grease1,
|
||||
&reneg,
|
||||
&sni,
|
||||
&ems,
|
||||
&sessionTicket,
|
||||
&sigAndHash,
|
||||
&status,
|
||||
&sct,
|
||||
&alpn,
|
||||
&channelId,
|
||||
&points,
|
||||
&curves,
|
||||
&grease2,
|
||||
&padding,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uconn *UConn) parrotRandomizedALPN() error {
|
||||
err := uconn.parrotRandomizedNoALPN()
|
||||
if len(uconn.config.NextProtos) == 0 {
|
||||
// if user didn't specify alpn, choose something popular
|
||||
uconn.config.NextProtos = []string{"h2", "http/1.1"}
|
||||
}
|
||||
alpn := ALPNExtension{AlpnProtocols: uconn.config.NextProtos}
|
||||
uconn.Extensions = append(uconn.Extensions, &alpn)
|
||||
return err
|
||||
}
|
||||
|
||||
func (uconn *UConn) parrotRandomizedNoALPN() error {
|
||||
hello := uconn.HandshakeState.Hello
|
||||
session := uconn.HandshakeState.Session
|
||||
|
||||
hello.CipherSuites = make([]uint16, len(defaultCipherSuites()))
|
||||
copy(hello.CipherSuites, defaultCipherSuites())
|
||||
hello.CipherSuites = removeRandomCiphers(hello.CipherSuites, 0.4)
|
||||
err := shuffleCiphers(hello.CipherSuites)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = uconn.fillClientHelloHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sni := SNIExtension{uconn.config.ServerName}
|
||||
sessionTicket := SessionTicketExtension{Session: session}
|
||||
if session != nil {
|
||||
sessionTicket.Session = session
|
||||
if len(session.SessionTicket()) > 0 {
|
||||
sessionId := sha256.Sum256(session.SessionTicket())
|
||||
hello.SessionId = sessionId[:]
|
||||
}
|
||||
}
|
||||
sigAndHashAlgos := []SignatureAndHash{
|
||||
{hashSHA256, signatureECDSA},
|
||||
{hashSHA256, signatureRSA},
|
||||
{hashSHA384, signatureECDSA},
|
||||
{hashSHA384, signatureRSA},
|
||||
{hashSHA1, signatureRSA},
|
||||
}
|
||||
if tossBiasedCoin(0.5) {
|
||||
sigAndHashAlgos = append(sigAndHashAlgos, SignatureAndHash{disabledHashSHA512, signatureECDSA})
|
||||
appendToGlobalSigAlgs(disabledHashSHA512, signatureECDSA)
|
||||
}
|
||||
if tossBiasedCoin(0.5) {
|
||||
sigAndHashAlgos = append(sigAndHashAlgos, SignatureAndHash{disabledHashSHA512, signatureRSA})
|
||||
appendToGlobalSigAlgs(disabledHashSHA512, signatureRSA)
|
||||
}
|
||||
if tossBiasedCoin(0.5) {
|
||||
sigAndHashAlgos = append(sigAndHashAlgos, SignatureAndHash{hashSHA1, signatureECDSA})
|
||||
}
|
||||
err = shuffleSignatures(sigAndHashAlgos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigAndHash := SignatureAlgorithmsExtension{SignatureAndHashes: sigAndHashAlgos}
|
||||
|
||||
status := StatusRequestExtension{}
|
||||
sct := SCTExtension{}
|
||||
points := SupportedPointsExtension{SupportedPoints: []byte{pointFormatUncompressed}}
|
||||
|
||||
curveIDs := []CurveID{}
|
||||
if tossBiasedCoin(0.7) {
|
||||
curveIDs = append(curveIDs, X25519)
|
||||
}
|
||||
curveIDs = append(curveIDs, CurveP256, CurveP384)
|
||||
if tossBiasedCoin(0.3) {
|
||||
curveIDs = append(curveIDs, CurveP521)
|
||||
}
|
||||
curves := SupportedCurvesExtension{curveIDs}
|
||||
|
||||
padding := FakePaddingExtension{GetPaddingLen: boringPaddingStyle}
|
||||
reneg := RenegotiationInfoExtension{renegotiation: RenegotiateOnceAsClient}
|
||||
|
||||
uconn.Extensions = []TLSExtension{
|
||||
&sni,
|
||||
&sessionTicket,
|
||||
&sigAndHash,
|
||||
&points,
|
||||
&curves,
|
||||
}
|
||||
|
||||
if tossBiasedCoin(0.66) {
|
||||
uconn.Extensions = append(uconn.Extensions, &padding)
|
||||
}
|
||||
if tossBiasedCoin(0.66) {
|
||||
uconn.Extensions = append(uconn.Extensions, &status)
|
||||
}
|
||||
if tossBiasedCoin(0.55) {
|
||||
uconn.Extensions = append(uconn.Extensions, &sct)
|
||||
}
|
||||
if tossBiasedCoin(0.44) {
|
||||
uconn.Extensions = append(uconn.Extensions, &reneg)
|
||||
}
|
||||
err = shuffleTLSExtensions(uconn.Extensions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uconn *UConn) parrotCustom() error {
|
||||
return uconn.fillClientHelloHeader()
|
||||
}
|
||||
|
||||
func tossBiasedCoin(probability float32) bool {
|
||||
// probability is expected to be in [0,1]
|
||||
// this function never returns errors for ease of use
|
||||
const precision = 0xffff
|
||||
threshold := float32(precision) * probability
|
||||
value, err := getRandInt(precision)
|
||||
if err != nil {
|
||||
// I doubt that this code will ever actually be used, as other functions are expected to complain
|
||||
// about used source of entropy. Nonetheless, this is more than enough for given purpose
|
||||
return ((time.Now().Unix() & 1) == 0)
|
||||
}
|
||||
|
||||
if float32(value) <= threshold {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func removeRandomCiphers(s []uint16, maxRemovalProbability float32) []uint16 {
|
||||
// removes elements in place
|
||||
// probability to remove increases for further elements
|
||||
// never remove first cipher
|
||||
if len(s) <= 1 {
|
||||
return s
|
||||
}
|
||||
|
||||
// remove random elements
|
||||
floatLen := float32(len(s))
|
||||
sliceLen := len(s)
|
||||
for i := 1; i < sliceLen; i++ {
|
||||
if tossBiasedCoin(maxRemovalProbability * float32(i) / floatLen) {
|
||||
s = append(s[:i], s[i+1:]...)
|
||||
sliceLen--
|
||||
i--
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func getRandInt(max int) (int, error) {
|
||||
bigInt, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
|
||||
return int(bigInt.Int64()), err
|
||||
}
|
||||
|
||||
func getRandPerm(n int) ([]int, error) {
|
||||
permArray := make([]int, n)
|
||||
for i := 1; i < n; i++ {
|
||||
j, err := getRandInt(i + 1)
|
||||
if err != nil {
|
||||
return permArray, err
|
||||
}
|
||||
permArray[i] = permArray[j]
|
||||
permArray[j] = i
|
||||
}
|
||||
return permArray, nil
|
||||
}
|
||||
|
||||
func shuffleCiphers(s []uint16) error {
|
||||
// shuffles array in place
|
||||
ciphers := make(sortableCiphers, len(cipherSuites))
|
||||
perm, err := getRandPerm(len(cipherSuites))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, suite := range cipherSuites {
|
||||
ciphers[i] = sortableCipher{suite: suite.id,
|
||||
isObsolete: ((suite.flags & suiteTLS12) == 0),
|
||||
randomTag: perm[i]}
|
||||
}
|
||||
sort.Sort(ciphers)
|
||||
s = ciphers.GetCiphers()
|
||||
return nil
|
||||
}
|
||||
|
||||
type sortableCipher struct {
|
||||
isObsolete bool
|
||||
randomTag int
|
||||
suite uint16
|
||||
}
|
||||
|
||||
type sortableCiphers []sortableCipher
|
||||
|
||||
func (ciphers sortableCiphers) Len() int {
|
||||
return len(ciphers)
|
||||
}
|
||||
|
||||
func (ciphers sortableCiphers) Less(i, j int) bool {
|
||||
if ciphers[i].isObsolete && !ciphers[j].isObsolete {
|
||||
return false
|
||||
}
|
||||
if ciphers[j].isObsolete && !ciphers[i].isObsolete {
|
||||
return true
|
||||
}
|
||||
return ciphers[i].randomTag < ciphers[j].randomTag
|
||||
}
|
||||
|
||||
func (ciphers sortableCiphers) Swap(i, j int) {
|
||||
ciphers[i], ciphers[j] = ciphers[j], ciphers[i]
|
||||
}
|
||||
|
||||
func (ciphers sortableCiphers) GetCiphers() []uint16 {
|
||||
cipherIDs := make([]uint16, len(ciphers))
|
||||
for i := range ciphers {
|
||||
cipherIDs[i] = ciphers[i].suite
|
||||
}
|
||||
return cipherIDs
|
||||
}
|
||||
|
||||
// so much for generics
|
||||
func shuffleTLSExtensions(s []TLSExtension) error {
|
||||
// shuffles array in place
|
||||
perm, err := getRandPerm(len(s))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range s {
|
||||
s[i], s[perm[i]] = s[perm[i]], s[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// so much for generics
|
||||
func shuffleSignatures(s []SignatureAndHash) error {
|
||||
// shuffles array in place
|
||||
perm, err := getRandPerm(len(s))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range s {
|
||||
s[i], s[perm[i]] = s[perm[i]], s[i]
|
||||
}
|
||||
return nil
|
||||
}
|
383
u_public.go
Normal file
383
u_public.go
Normal file
|
@ -0,0 +1,383 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/x509"
|
||||
"hash"
|
||||
)
|
||||
|
||||
type ClientHandshakeState struct {
|
||||
C *Conn
|
||||
ServerHello *ServerHelloMsg
|
||||
Hello *ClientHelloMsg
|
||||
Suite *CipherSuite
|
||||
FinishedHash FinishedHash
|
||||
MasterSecret []byte
|
||||
Session *ClientSessionState
|
||||
}
|
||||
|
||||
// getPrivatePtr() methods make shallow copies
|
||||
|
||||
func (chs *ClientHandshakeState) getPrivatePtr() *clientHandshakeState {
|
||||
if chs == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &clientHandshakeState{
|
||||
c: chs.C,
|
||||
serverHello: chs.ServerHello.getPrivatePtr(),
|
||||
hello: chs.Hello.getPrivatePtr(),
|
||||
suite: chs.Suite.getPrivatePtr(),
|
||||
finishedHash: *chs.FinishedHash.getPrivatePtr(),
|
||||
masterSecret: chs.MasterSecret,
|
||||
session: chs.Session,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (chs *clientHandshakeState) getPublicPtr() *ClientHandshakeState {
|
||||
if chs == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &ClientHandshakeState{
|
||||
C: chs.c,
|
||||
ServerHello: chs.serverHello.getPublicPtr(),
|
||||
Hello: chs.hello.getPublicPtr(),
|
||||
Suite: chs.suite.getPublicPtr(),
|
||||
FinishedHash: *chs.finishedHash.getPublicPtr(),
|
||||
MasterSecret: chs.masterSecret,
|
||||
Session: chs.session,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type BensStruct serverHelloMsg
|
||||
|
||||
type ServerHelloMsg struct {
|
||||
Raw []byte
|
||||
Vers uint16
|
||||
Random []byte
|
||||
SessionId []byte
|
||||
CipherSuite uint16
|
||||
CompressionMethod uint8
|
||||
NextProtoNeg bool
|
||||
NextProtos []string
|
||||
OcspStapling bool
|
||||
Scts [][]byte
|
||||
TicketSupported bool
|
||||
SecureRenegotiation []byte
|
||||
SecureRenegotiationSupported bool
|
||||
AlpnProtocol string
|
||||
}
|
||||
|
||||
func (shm *ServerHelloMsg) getPrivatePtr() *serverHelloMsg {
|
||||
if shm == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &serverHelloMsg{
|
||||
raw: shm.Raw,
|
||||
vers: shm.Vers,
|
||||
random: shm.Random,
|
||||
sessionId: shm.SessionId,
|
||||
cipherSuite: shm.CipherSuite,
|
||||
compressionMethod: shm.CompressionMethod,
|
||||
nextProtoNeg: shm.NextProtoNeg,
|
||||
nextProtos: shm.NextProtos,
|
||||
ocspStapling: shm.OcspStapling,
|
||||
scts: shm.Scts,
|
||||
ticketSupported: shm.TicketSupported,
|
||||
secureRenegotiation: shm.SecureRenegotiation,
|
||||
secureRenegotiationSupported: shm.SecureRenegotiationSupported,
|
||||
alpnProtocol: shm.AlpnProtocol,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (shm *serverHelloMsg) getPublicPtr() *ServerHelloMsg {
|
||||
if shm == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &ServerHelloMsg{
|
||||
Raw: shm.raw,
|
||||
Vers: shm.vers,
|
||||
Random: shm.random,
|
||||
SessionId: shm.sessionId,
|
||||
CipherSuite: shm.cipherSuite,
|
||||
CompressionMethod: shm.compressionMethod,
|
||||
NextProtoNeg: shm.nextProtoNeg,
|
||||
NextProtos: shm.nextProtos,
|
||||
OcspStapling: shm.ocspStapling,
|
||||
Scts: shm.scts,
|
||||
TicketSupported: shm.ticketSupported,
|
||||
SecureRenegotiation: shm.secureRenegotiation,
|
||||
SecureRenegotiationSupported: shm.secureRenegotiationSupported,
|
||||
AlpnProtocol: shm.alpnProtocol,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ClientHelloMsg struct {
|
||||
Raw []byte
|
||||
Vers uint16
|
||||
Random []byte
|
||||
SessionId []byte
|
||||
CipherSuites []uint16
|
||||
CompressionMethods []uint8
|
||||
NextProtoNeg bool
|
||||
ServerName string
|
||||
OcspStapling bool
|
||||
Scts bool
|
||||
SupportedCurves []CurveID
|
||||
SupportedPoints []uint8
|
||||
TicketSupported bool
|
||||
SessionTicket []uint8
|
||||
SignatureAndHashes []SignatureAndHash
|
||||
SecureRenegotiation []byte
|
||||
SecureRenegotiationSupported bool
|
||||
AlpnProtocols []string
|
||||
}
|
||||
|
||||
func (chm *ClientHelloMsg) getPrivatePtr() *clientHelloMsg {
|
||||
if chm == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &clientHelloMsg{
|
||||
raw: chm.Raw,
|
||||
vers: chm.Vers,
|
||||
random: chm.Random,
|
||||
sessionId: chm.SessionId,
|
||||
cipherSuites: chm.CipherSuites,
|
||||
compressionMethods: chm.CompressionMethods,
|
||||
nextProtoNeg: chm.NextProtoNeg,
|
||||
serverName: chm.ServerName,
|
||||
ocspStapling: chm.OcspStapling,
|
||||
scts: chm.Scts,
|
||||
supportedCurves: chm.SupportedCurves,
|
||||
supportedPoints: chm.SupportedPoints,
|
||||
ticketSupported: chm.TicketSupported,
|
||||
sessionTicket: chm.SessionTicket,
|
||||
signatureAndHashes: sigAndHashGetMakePrivate(chm.SignatureAndHashes),
|
||||
secureRenegotiation: chm.SecureRenegotiation,
|
||||
secureRenegotiationSupported: chm.SecureRenegotiationSupported,
|
||||
alpnProtocols: chm.AlpnProtocols,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (chm *clientHelloMsg) getPublicPtr() *ClientHelloMsg {
|
||||
if chm == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &ClientHelloMsg{
|
||||
Raw: chm.raw,
|
||||
Vers: chm.vers,
|
||||
Random: chm.random,
|
||||
SessionId: chm.sessionId,
|
||||
CipherSuites: chm.cipherSuites,
|
||||
CompressionMethods: chm.compressionMethods,
|
||||
NextProtoNeg: chm.nextProtoNeg,
|
||||
ServerName: chm.serverName,
|
||||
OcspStapling: chm.ocspStapling,
|
||||
Scts: chm.scts,
|
||||
SupportedCurves: chm.supportedCurves,
|
||||
SupportedPoints: chm.supportedPoints,
|
||||
TicketSupported: chm.ticketSupported,
|
||||
SessionTicket: chm.sessionTicket,
|
||||
SignatureAndHashes: sigAndHashMakePublic(chm.signatureAndHashes),
|
||||
SecureRenegotiation: chm.secureRenegotiation,
|
||||
SecureRenegotiationSupported: chm.secureRenegotiationSupported,
|
||||
AlpnProtocols: chm.alpnProtocols,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SignatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See
|
||||
// RFC 5246, section A.4.1.
|
||||
type SignatureAndHash struct {
|
||||
Hash, Signature uint8
|
||||
}
|
||||
|
||||
func sigAndHashGetMakePrivate(sahSlice []SignatureAndHash) []signatureAndHash {
|
||||
res := []signatureAndHash{}
|
||||
for _, sah := range sahSlice {
|
||||
res = append(res, signatureAndHash{hash: sah.Hash,
|
||||
signature: sah.Signature})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func sigAndHashMakePublic(sahSlice []signatureAndHash) []SignatureAndHash {
|
||||
res := []SignatureAndHash{}
|
||||
for _, sah := range sahSlice {
|
||||
res = append(res, SignatureAndHash{Hash: sah.hash,
|
||||
Signature: sah.signature})
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// A CipherSuite is a specific combination of key agreement, cipher and MAC
|
||||
// function. All cipher suites currently assume RSA key agreement.
|
||||
type CipherSuite struct {
|
||||
Id uint16
|
||||
// the lengths, in bytes, of the key material needed for each component.
|
||||
KeyLen int
|
||||
MacLen int
|
||||
IvLen int
|
||||
Ka func(version uint16) keyAgreement
|
||||
// flags is a bitmask of the suite* values, above.
|
||||
Flags int
|
||||
Cipher func(key, iv []byte, isRead bool) interface{}
|
||||
Mac func(version uint16, macKey []byte) macFunction
|
||||
Aead func(key, fixedNonce []byte) cipher.AEAD
|
||||
}
|
||||
|
||||
func (cs *CipherSuite) getPrivatePtr() *cipherSuite {
|
||||
if cs == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &cipherSuite{
|
||||
id: cs.Id,
|
||||
keyLen: cs.KeyLen,
|
||||
macLen: cs.MacLen,
|
||||
ivLen: cs.IvLen,
|
||||
ka: cs.Ka,
|
||||
flags: cs.Flags,
|
||||
cipher: cs.Cipher,
|
||||
mac: cs.Mac,
|
||||
aead: cs.Aead,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *cipherSuite) getPublicPtr() *CipherSuite {
|
||||
if cs == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &CipherSuite{
|
||||
Id: cs.id,
|
||||
KeyLen: cs.keyLen,
|
||||
MacLen: cs.macLen,
|
||||
IvLen: cs.ivLen,
|
||||
Ka: cs.ka,
|
||||
Flags: cs.flags,
|
||||
Cipher: cs.cipher,
|
||||
Mac: cs.mac,
|
||||
Aead: cs.aead,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A FinishedHash calculates the hash of a set of handshake messages suitable
|
||||
// for including in a Finished message.
|
||||
type FinishedHash struct {
|
||||
Client hash.Hash
|
||||
Server hash.Hash
|
||||
|
||||
// Prior to TLS 1.2, an additional MD5 hash is required.
|
||||
ClientMD5 hash.Hash
|
||||
ServerMD5 hash.Hash
|
||||
|
||||
// In TLS 1.2, a full buffer is sadly required.
|
||||
Buffer []byte
|
||||
|
||||
Version uint16
|
||||
Prf func(result, secret, label, seed []byte)
|
||||
}
|
||||
|
||||
func (fh *FinishedHash) getPrivatePtr() *finishedHash {
|
||||
if fh == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &finishedHash{
|
||||
client: fh.Client,
|
||||
server: fh.Server,
|
||||
clientMD5: fh.ClientMD5,
|
||||
serverMD5: fh.ServerMD5,
|
||||
buffer: fh.Buffer,
|
||||
version: fh.Version,
|
||||
prf: fh.Prf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fh *finishedHash) getPublicPtr() *FinishedHash {
|
||||
if fh == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &FinishedHash{
|
||||
Client: fh.client,
|
||||
Server: fh.server,
|
||||
ClientMD5: fh.clientMD5,
|
||||
ServerMD5: fh.serverMD5,
|
||||
Buffer: fh.buffer,
|
||||
Version: fh.version,
|
||||
Prf: fh.prf}
|
||||
}
|
||||
}
|
||||
|
||||
// ClientSessionState is public, but all its fields are private. Let's add setters, getters and constructor
|
||||
|
||||
// ClientSessionState contains the state needed by clients to resume TLS sessions.
|
||||
func MakeClientSessionState(
|
||||
SessionTicket []uint8,
|
||||
Vers uint16,
|
||||
CipherSuite uint16,
|
||||
MasterSecret []byte,
|
||||
ServerCertificates []*x509.Certificate,
|
||||
VerifiedChains [][]*x509.Certificate) *ClientSessionState {
|
||||
css := ClientSessionState{sessionTicket: SessionTicket,
|
||||
vers: Vers,
|
||||
cipherSuite: CipherSuite,
|
||||
masterSecret: MasterSecret,
|
||||
serverCertificates: ServerCertificates,
|
||||
verifiedChains: VerifiedChains}
|
||||
return &css
|
||||
}
|
||||
|
||||
// Encrypted ticket used for session resumption with server
|
||||
func (css *ClientSessionState) SessionTicket() []uint8 {
|
||||
return css.sessionTicket
|
||||
}
|
||||
|
||||
// SSL/TLS version negotiated for the session
|
||||
func (css *ClientSessionState) Vers() uint16 {
|
||||
return css.vers
|
||||
}
|
||||
|
||||
// Ciphersuite negotiated for the session
|
||||
func (css *ClientSessionState) CipherSuite() uint16 {
|
||||
return css.cipherSuite
|
||||
}
|
||||
|
||||
// MasterSecret generated by client on a full handshake
|
||||
func (css *ClientSessionState) MasterSecret() []byte {
|
||||
return css.masterSecret
|
||||
}
|
||||
|
||||
// Certificate chain presented by the server
|
||||
func (css *ClientSessionState) ServerCertificates() []*x509.Certificate {
|
||||
return css.serverCertificates
|
||||
}
|
||||
|
||||
// Certificate chains we built for verification
|
||||
func (css *ClientSessionState) VerifiedChains() [][]*x509.Certificate {
|
||||
return css.verifiedChains
|
||||
}
|
||||
|
||||
func (css *ClientSessionState) SetSessionTicket(SessionTicket []uint8) {
|
||||
css.sessionTicket = SessionTicket
|
||||
}
|
||||
func (css *ClientSessionState) SetVers(Vers uint16) {
|
||||
css.vers = Vers
|
||||
}
|
||||
func (css *ClientSessionState) SetCipherSuite(CipherSuite uint16) {
|
||||
css.cipherSuite = CipherSuite
|
||||
}
|
||||
func (css *ClientSessionState) SetMasterSecret(MasterSecret []byte) {
|
||||
css.masterSecret = MasterSecret
|
||||
}
|
||||
func (css *ClientSessionState) SetServerCertificates(ServerCertificates []*x509.Certificate) {
|
||||
css.serverCertificates = ServerCertificates
|
||||
}
|
||||
func (css *ClientSessionState) SetVerifiedChains(VerifiedChains [][]*x509.Certificate) {
|
||||
css.verifiedChains = VerifiedChains
|
||||
}
|
506
u_tls_extensions.go
Normal file
506
u_tls_extensions.go
Normal file
|
@ -0,0 +1,506 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type NPNExtension struct {
|
||||
NextProtos []string
|
||||
}
|
||||
|
||||
func (e *NPNExtension) writeToUConn(uc *UConn) error {
|
||||
uc.config.NextProtos = e.NextProtos
|
||||
uc.HandshakeState.Hello.NextProtoNeg = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *NPNExtension) Len() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (e *NPNExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
b[0] = byte(extensionNextProtoNeg >> 8)
|
||||
b[1] = byte(extensionNextProtoNeg & 0xff)
|
||||
// The length is always 0
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type SNIExtension struct {
|
||||
ServerName string // not an array because go crypto/tls doesn't support multiple SNIs
|
||||
}
|
||||
|
||||
func (e *SNIExtension) writeToUConn(uc *UConn) error {
|
||||
uc.config.ServerName = e.ServerName
|
||||
uc.HandshakeState.Hello.ServerName = e.ServerName
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *SNIExtension) Len() int {
|
||||
return 4 + 2 + 1 + 2 + len(e.ServerName)
|
||||
}
|
||||
|
||||
func (e *SNIExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// RFC 3546, section 3.1
|
||||
b[0] = byte(extensionServerName >> 8)
|
||||
b[1] = byte(extensionServerName)
|
||||
b[2] = byte((len(e.ServerName) + 5) >> 8)
|
||||
b[3] = byte((len(e.ServerName) + 5))
|
||||
b[4] = byte((len(e.ServerName) + 3) >> 8)
|
||||
b[5] = byte(len(e.ServerName) + 3)
|
||||
// b[6] Server Name Type: host_name (0)
|
||||
b[7] = byte(len(e.ServerName) >> 8)
|
||||
b[8] = byte(len(e.ServerName))
|
||||
copy(b[9:], []byte(e.ServerName))
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type StatusRequestExtension struct {
|
||||
}
|
||||
|
||||
func (e *StatusRequestExtension) writeToUConn(uc *UConn) error {
|
||||
uc.HandshakeState.Hello.OcspStapling = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *StatusRequestExtension) Len() int {
|
||||
return 9
|
||||
}
|
||||
|
||||
func (e *StatusRequestExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// RFC 4366, section 3.6
|
||||
b[0] = byte(extensionStatusRequest >> 8)
|
||||
b[1] = byte(extensionStatusRequest)
|
||||
b[2] = 0
|
||||
b[3] = 5
|
||||
b[4] = 1 // OCSP type
|
||||
// Two zero valued uint16s for the two lengths.
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type SupportedCurvesExtension struct {
|
||||
Curves []CurveID
|
||||
}
|
||||
|
||||
func (e *SupportedCurvesExtension) writeToUConn(uc *UConn) error {
|
||||
uc.config.CurvePreferences = e.Curves
|
||||
uc.HandshakeState.Hello.SupportedCurves = e.Curves
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *SupportedCurvesExtension) Len() int {
|
||||
return 6 + 2*len(e.Curves)
|
||||
}
|
||||
|
||||
func (e *SupportedCurvesExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// http://tools.ietf.org/html/rfc4492#section-5.5.1
|
||||
b[0] = byte(extensionSupportedCurves >> 8)
|
||||
b[1] = byte(extensionSupportedCurves)
|
||||
b[2] = byte((2 + 2*len(e.Curves)) >> 8)
|
||||
b[3] = byte((2 + 2*len(e.Curves)))
|
||||
b[4] = byte((2 * len(e.Curves)) >> 8)
|
||||
b[5] = byte((2 * len(e.Curves)))
|
||||
for i, curve := range e.Curves {
|
||||
b[6+2*i] = byte(curve >> 8)
|
||||
b[7+2*i] = byte(curve)
|
||||
}
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type SupportedPointsExtension struct {
|
||||
SupportedPoints []uint8
|
||||
}
|
||||
|
||||
func (e *SupportedPointsExtension) writeToUConn(uc *UConn) error {
|
||||
uc.HandshakeState.Hello.SupportedPoints = e.SupportedPoints
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *SupportedPointsExtension) Len() int {
|
||||
return 5 + len(e.SupportedPoints)
|
||||
}
|
||||
|
||||
func (e *SupportedPointsExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// http://tools.ietf.org/html/rfc4492#section-5.5.2
|
||||
b[0] = byte(extensionSupportedPoints >> 8)
|
||||
b[1] = byte(extensionSupportedPoints)
|
||||
b[2] = byte((1 + len(e.SupportedPoints)) >> 8)
|
||||
b[3] = byte((1 + len(e.SupportedPoints)))
|
||||
b[4] = byte((len(e.SupportedPoints)))
|
||||
for i, pointFormat := range e.SupportedPoints {
|
||||
b[5+i] = pointFormat
|
||||
}
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type SignatureAlgorithmsExtension struct {
|
||||
SignatureAndHashes []SignatureAndHash
|
||||
}
|
||||
|
||||
func (e *SignatureAlgorithmsExtension) writeToUConn(uc *UConn) error {
|
||||
uc.HandshakeState.Hello.SignatureAndHashes = e.SignatureAndHashes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *SignatureAlgorithmsExtension) Len() int {
|
||||
return 6 + 2*len(e.SignatureAndHashes)
|
||||
}
|
||||
|
||||
func (e *SignatureAlgorithmsExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
||||
b[0] = byte(extensionSignatureAlgorithms >> 8)
|
||||
b[1] = byte(extensionSignatureAlgorithms)
|
||||
b[2] = byte((2 + 2*len(e.SignatureAndHashes)) >> 8)
|
||||
b[3] = byte((2 + 2*len(e.SignatureAndHashes)))
|
||||
b[4] = byte((2 * len(e.SignatureAndHashes)) >> 8)
|
||||
b[5] = byte((2 * len(e.SignatureAndHashes)))
|
||||
for i, sigAndHash := range e.SignatureAndHashes {
|
||||
b[6+2*i] = byte(sigAndHash.Hash)
|
||||
b[7+2*i] = byte(sigAndHash.Signature)
|
||||
}
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type RenegotiationInfoExtension struct {
|
||||
renegotiation RenegotiationSupport
|
||||
SecureRenegotiation []byte // you probably want to leave it empty
|
||||
}
|
||||
|
||||
func (e *RenegotiationInfoExtension) writeToUConn(uc *UConn) error {
|
||||
uc.config.Renegotiation = e.renegotiation
|
||||
switch e.renegotiation {
|
||||
case RenegotiateOnceAsClient:
|
||||
fallthrough
|
||||
case RenegotiateFreelyAsClient:
|
||||
uc.HandshakeState.Hello.SecureRenegotiationSupported = true
|
||||
// Note that if we manage to use this in renegotiation(currently only in initial handshake), we'd have to point
|
||||
// uc.HandshakeState.Hello.SecureRenegotiation = chs.C.clientFinished
|
||||
// and probably do something else. It's a mess.
|
||||
case RenegotiateNever:
|
||||
default:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *RenegotiationInfoExtension) Len() int {
|
||||
switch e.renegotiation {
|
||||
case RenegotiateOnceAsClient:
|
||||
fallthrough
|
||||
case RenegotiateFreelyAsClient:
|
||||
return 5 + len(e.SecureRenegotiation)
|
||||
case RenegotiateNever:
|
||||
default:
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *RenegotiationInfoExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
switch e.renegotiation {
|
||||
case RenegotiateOnceAsClient:
|
||||
fallthrough
|
||||
case RenegotiateFreelyAsClient:
|
||||
b[0] = byte(extensionRenegotiationInfo >> 8)
|
||||
b[1] = byte(extensionRenegotiationInfo & 0xff)
|
||||
b[2] = 0 // TODO: this is not what Chrome does :(
|
||||
b[3] = byte(len(e.SecureRenegotiation) + 1)
|
||||
b[4] = byte(len(e.SecureRenegotiation))
|
||||
if len(e.SecureRenegotiation) != 0 {
|
||||
copy(b[5:], e.SecureRenegotiation)
|
||||
}
|
||||
case RenegotiateNever:
|
||||
default:
|
||||
}
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type ALPNExtension struct {
|
||||
AlpnProtocols []string
|
||||
}
|
||||
|
||||
func (e *ALPNExtension) writeToUConn(uc *UConn) error {
|
||||
uc.config.NextProtos = e.AlpnProtocols
|
||||
uc.HandshakeState.Hello.AlpnProtocols = e.AlpnProtocols
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ALPNExtension) Len() int {
|
||||
bLen := 2 + 2 + 2
|
||||
for _, s := range e.AlpnProtocols {
|
||||
bLen += 1 + len(s)
|
||||
}
|
||||
return bLen
|
||||
}
|
||||
|
||||
func (e *ALPNExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
|
||||
b[0] = byte(extensionALPN >> 8)
|
||||
b[1] = byte(extensionALPN & 0xff)
|
||||
lengths := b[2:]
|
||||
b = b[6:]
|
||||
|
||||
stringsLength := 0
|
||||
for _, s := range e.AlpnProtocols {
|
||||
l := len(s)
|
||||
b[0] = byte(l)
|
||||
copy(b[1:], s)
|
||||
b = b[1+l:]
|
||||
stringsLength += 1 + l
|
||||
}
|
||||
|
||||
lengths[2] = byte(stringsLength >> 8)
|
||||
lengths[3] = byte(stringsLength)
|
||||
stringsLength += 2
|
||||
lengths[0] = byte(stringsLength >> 8)
|
||||
lengths[1] = byte(stringsLength)
|
||||
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type SCTExtension struct {
|
||||
}
|
||||
|
||||
func (e *SCTExtension) writeToUConn(uc *UConn) error {
|
||||
uc.HandshakeState.Hello.Scts = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *SCTExtension) Len() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (e *SCTExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// https://tools.ietf.org/html/rfc6962#section-3.3.1
|
||||
b[0] = byte(extensionSCT >> 8)
|
||||
b[1] = byte(extensionSCT)
|
||||
// zero uint16 for the zero-length extension_data
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type SessionTicketExtension struct {
|
||||
Session *ClientSessionState
|
||||
}
|
||||
|
||||
func (e *SessionTicketExtension) writeToUConn(uc *UConn) error {
|
||||
if e.Session != nil {
|
||||
uc.HandshakeState.Session = e.Session
|
||||
uc.HandshakeState.Hello.SessionTicket = e.Session.sessionTicket
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *SessionTicketExtension) Len() int {
|
||||
if e.Session != nil {
|
||||
return 4 + len(e.Session.sessionTicket)
|
||||
}
|
||||
return 4
|
||||
}
|
||||
|
||||
func (e *SessionTicketExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
|
||||
extBodyLen := e.Len() - 4
|
||||
|
||||
b[0] = byte(extensionSessionTicket >> 8)
|
||||
b[1] = byte(extensionSessionTicket)
|
||||
b[2] = byte(extBodyLen >> 8)
|
||||
b[3] = byte(extBodyLen)
|
||||
if extBodyLen > 0 {
|
||||
copy(b[4:], e.Session.sessionTicket)
|
||||
}
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
/*
|
||||
FAKE EXTENSIONS
|
||||
*/
|
||||
|
||||
type FakeChannelIDExtension struct {
|
||||
}
|
||||
|
||||
func (e *FakeChannelIDExtension) writeToUConn(uc *UConn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *FakeChannelIDExtension) Len() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (e *FakeChannelIDExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// https://tools.ietf.org/html/draft-balfanz-tls-channelid-00
|
||||
b[0] = byte(fakeExtensionChannelID >> 8)
|
||||
b[1] = byte(fakeExtensionChannelID & 0xff)
|
||||
// The length is 0
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
type FakeExtendedMasterSecretExtension struct {
|
||||
}
|
||||
|
||||
// TODO: update when Cloudflare upstreams this extension to crypto/tls
|
||||
// but we probably won't have to enable it in Config
|
||||
func (e *FakeExtendedMasterSecretExtension) writeToUConn(uc *UConn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *FakeExtendedMasterSecretExtension) Len() int {
|
||||
return 4
|
||||
}
|
||||
|
||||
func (e *FakeExtendedMasterSecretExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// https://tools.ietf.org/html/rfc7627
|
||||
b[0] = byte(fakeExtensionExtendedMasterSecret >> 8)
|
||||
b[1] = byte(fakeExtensionExtendedMasterSecret)
|
||||
// The length is 0
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
// GREASE stinks with dead parrots, have to be super careful, and, if possible, not include GREASE
|
||||
const (
|
||||
ssl_grease_cipher = iota
|
||||
ssl_grease_group
|
||||
ssl_grease_extension1
|
||||
ssl_grease_extension2
|
||||
ssl_grease_version
|
||||
ssl_grease_ticket_extension
|
||||
)
|
||||
|
||||
// it is responsibility of user not to generate multiple grease extensions with same value
|
||||
type FakeGREASEExtension struct {
|
||||
Value uint16
|
||||
Body []byte // in Chrome first grease has empty body, second grease has a single zero byte
|
||||
}
|
||||
|
||||
func (e *FakeGREASEExtension) writeToUConn(uc *UConn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// will panic if clientRandom[index] is out of bounds.
|
||||
func GetBoringGREASEValue(clientRandom []byte, index int) uint16 {
|
||||
// Get GREASE value BoringSSL-style. Unfortunately, this value isn't really boring and is quite interesting :(
|
||||
// https://github.com/google/boringssl/blob/a365138ac60f38b64bfc608b493e0f879845cb88/ssl/handshake_client.c#L530
|
||||
ret := uint16(clientRandom[index])
|
||||
/* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */
|
||||
ret = (ret & 0xf0) | 0x0a
|
||||
ret |= ret << 8
|
||||
return ret
|
||||
}
|
||||
|
||||
func (e *FakeGREASEExtension) Len() int {
|
||||
return 4 + len(e.Body)
|
||||
}
|
||||
|
||||
func (e *FakeGREASEExtension) Read(b []byte) (int, error) {
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
|
||||
b[0] = byte(e.Value >> 8)
|
||||
b[1] = byte(e.Value)
|
||||
b[2] = byte(len(e.Body) >> 8)
|
||||
b[3] = byte(len(e.Body))
|
||||
if len(e.Body) > 0 {
|
||||
copy(b[4:], e.Body)
|
||||
}
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
//
|
||||
type FakePaddingExtension struct {
|
||||
PaddingLen int
|
||||
WillPad bool // set to false to disable extension
|
||||
|
||||
// Functor for deciding on padding length based on unpadded ClientHello length.
|
||||
// If willPad is false, then this extension should not be included.
|
||||
GetPaddingLen func(clientHelloUnpaddedLen int) (paddingLen int, willPad bool)
|
||||
}
|
||||
|
||||
func (e *FakePaddingExtension) writeToUConn(uc *UConn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *FakePaddingExtension) Len() int {
|
||||
if e.WillPad {
|
||||
return 4 + e.PaddingLen
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (e *FakePaddingExtension) Update(clientHelloUnpaddedLen int) {
|
||||
if e.GetPaddingLen != nil {
|
||||
e.PaddingLen, e.WillPad = e.GetPaddingLen(clientHelloUnpaddedLen)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *FakePaddingExtension) Read(b []byte) (int, error) {
|
||||
if !e.WillPad {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if len(b) < e.Len() {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
// https://tools.ietf.org/html/rfc7627
|
||||
b[0] = byte(fakeExtensionPadding >> 8)
|
||||
b[1] = byte(fakeExtensionPadding)
|
||||
b[2] = byte(e.PaddingLen >> 8)
|
||||
b[3] = byte(e.PaddingLen)
|
||||
return e.Len(), io.EOF
|
||||
}
|
||||
|
||||
// https://github.com/google/boringssl/blob/7d7554b6b3c79e707e25521e61e066ce2b996e4c/ssl/t1_lib.c#L2803
|
||||
func boringPaddingStyle(unpaddedLen int) (int, bool) {
|
||||
if unpaddedLen > 0xff && unpaddedLen < 0x200 {
|
||||
paddingLen := 0x200 - unpaddedLen
|
||||
if paddingLen >= 4+1 {
|
||||
paddingLen -= 4
|
||||
} else {
|
||||
paddingLen = 1
|
||||
}
|
||||
return paddingLen, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue