crypto/tls: implement TLS 1.3 server PSK
This commit is contained in:
parent
453bd6af77
commit
ee3048cfd2
11
.travis.yml
11
.travis.yml
@ -8,21 +8,22 @@ go:
|
|||||||
- 1.7
|
- 1.7
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- MODE=gotest
|
|
||||||
- MODE=interop CLIENT=boring
|
- MODE=interop CLIENT=boring
|
||||||
- MODE=interop CLIENT=boring REVISION=origin/master
|
|
||||||
- MODE=interop CLIENT=bogo
|
- MODE=interop CLIENT=bogo
|
||||||
- MODE=interop CLIENT=bogo REVISION=origin/master
|
|
||||||
- MODE=interop CLIENT=tstclnt
|
- MODE=interop CLIENT=tstclnt
|
||||||
- MODE=interop CLIENT=tstclnt REVISION=default
|
|
||||||
- MODE=interop CLIENT=mint
|
- MODE=interop CLIENT=mint
|
||||||
|
- MODE=gotest
|
||||||
|
- MODE=interop CLIENT=boring REVISION=origin/master
|
||||||
|
- MODE=interop CLIENT=bogo REVISION=origin/master
|
||||||
|
- MODE=interop CLIENT=tstclnt REVISION=default
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- env: MODE=interop CLIENT=bogo REVISION=origin/master
|
|
||||||
- env: MODE=interop CLIENT=boring REVISION=origin/master
|
- env: MODE=interop CLIENT=boring REVISION=origin/master
|
||||||
|
- env: MODE=interop CLIENT=bogo REVISION=origin/master
|
||||||
- env: MODE=interop CLIENT=tstclnt REVISION=default
|
- env: MODE=interop CLIENT=tstclnt REVISION=default
|
||||||
|
- env: MODE=interop CLIENT=mint # broken resumption client
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- if [ "$MODE" = "interop" ]; then ./_dev/tris-localserver/start.sh -d && docker ps -a; fi
|
- if [ "$MODE" = "interop" ]; then ./_dev/tris-localserver/start.sh -d && docker ps -a; fi
|
||||||
|
248
13.go
248
13.go
@ -14,6 +14,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang_org/x/crypto/curve25519"
|
"golang_org/x/crypto/curve25519"
|
||||||
)
|
)
|
||||||
@ -55,6 +56,12 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
|
|||||||
}
|
}
|
||||||
hashSize := hash.Size()
|
hashSize := hash.Size()
|
||||||
|
|
||||||
|
earlySecret, isPSK := hs.checkPSK(hash)
|
||||||
|
if !isPSK {
|
||||||
|
earlySecret = hkdfExtract(hash, nil, nil)
|
||||||
|
}
|
||||||
|
c.didResume = isPSK
|
||||||
|
|
||||||
ecdheSecret := deriveECDHESecret(ks, privateKey)
|
ecdheSecret := deriveECDHESecret(ks, privateKey)
|
||||||
if ecdheSecret == nil {
|
if ecdheSecret == nil {
|
||||||
c.sendAlert(alertIllegalParameter)
|
c.sendAlert(alertIllegalParameter)
|
||||||
@ -69,9 +76,7 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
earlySecret := hkdfExtract(hash, nil, nil)
|
|
||||||
handshakeSecret := hkdfExtract(hash, ecdheSecret, earlySecret)
|
handshakeSecret := hkdfExtract(hash, ecdheSecret, earlySecret)
|
||||||
|
|
||||||
handshakeCtx := hs.finishedHash.Sum()
|
handshakeCtx := hs.finishedHash.Sum()
|
||||||
|
|
||||||
cHandshakeTS := hkdfExpandLabel(hash, handshakeSecret, handshakeCtx, "client handshake traffic secret", hashSize)
|
cHandshakeTS := hkdfExpandLabel(hash, handshakeSecret, handshakeCtx, "client handshake traffic secret", hashSize)
|
||||||
@ -91,6 +96,76 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isPSK {
|
||||||
|
if err := hs.sendCertificate13(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serverFinishedKey := hkdfExpandLabel(hash, sHandshakeTS, nil, "finished", hashSize)
|
||||||
|
clientFinishedKey := hkdfExpandLabel(hash, cHandshakeTS, nil, "finished", hashSize)
|
||||||
|
|
||||||
|
h := hmac.New(hash.New, serverFinishedKey)
|
||||||
|
h.Write(hs.finishedHash.Sum())
|
||||||
|
verifyData := h.Sum(nil)
|
||||||
|
serverFinished := &finishedMsg{
|
||||||
|
verifyData: verifyData,
|
||||||
|
}
|
||||||
|
hs.finishedHash.Write(serverFinished.marshal())
|
||||||
|
if _, err := c.writeRecord(recordTypeHandshake, serverFinished.marshal()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hs.masterSecret = hkdfExtract(hash, nil, handshakeSecret)
|
||||||
|
handshakeCtx = hs.finishedHash.Sum()
|
||||||
|
|
||||||
|
cTrafficSecret0 := hkdfExpandLabel(hash, hs.masterSecret, handshakeCtx, "client application traffic secret", hashSize)
|
||||||
|
cKey = hkdfExpandLabel(hash, cTrafficSecret0, nil, "key", hs.suite.keyLen)
|
||||||
|
cIV = hkdfExpandLabel(hash, cTrafficSecret0, nil, "iv", 12)
|
||||||
|
sTrafficSecret0 := hkdfExpandLabel(hash, hs.masterSecret, handshakeCtx, "server application traffic secret", hashSize)
|
||||||
|
sKey = hkdfExpandLabel(hash, sTrafficSecret0, nil, "key", hs.suite.keyLen)
|
||||||
|
sIV = hkdfExpandLabel(hash, sTrafficSecret0, nil, "iv", 12)
|
||||||
|
|
||||||
|
serverCipher = hs.suite.aead(sKey, sIV)
|
||||||
|
c.out.setCipher(c.vers, serverCipher)
|
||||||
|
|
||||||
|
// TODO(filippo): here we are ready to send Application Data, but we might want it opt-in.
|
||||||
|
// It will be refactored anyway for 0-RTT.
|
||||||
|
|
||||||
|
if _, err := c.flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := c.readHandshake()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
clientFinished, ok := msg.(*finishedMsg)
|
||||||
|
if !ok {
|
||||||
|
c.sendAlert(alertUnexpectedMessage)
|
||||||
|
return unexpectedMessageError(clientFinished, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
h = hmac.New(hash.New, clientFinishedKey)
|
||||||
|
h.Write(hs.finishedHash.Sum())
|
||||||
|
expectedVerifyData := h.Sum(nil)
|
||||||
|
if len(expectedVerifyData) != len(clientFinished.verifyData) ||
|
||||||
|
subtle.ConstantTimeCompare(expectedVerifyData, clientFinished.verifyData) != 1 {
|
||||||
|
c.sendAlert(alertHandshakeFailure)
|
||||||
|
return errors.New("tls: client's Finished message is incorrect")
|
||||||
|
}
|
||||||
|
hs.finishedHash.Write(clientFinished.marshal())
|
||||||
|
|
||||||
|
clientCipher = hs.suite.aead(cKey, cIV)
|
||||||
|
c.in.setCipher(c.vers, clientCipher)
|
||||||
|
|
||||||
|
return hs.sendSessionTicket13(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs *serverHandshakeState) sendCertificate13() error {
|
||||||
|
c := hs.c
|
||||||
|
|
||||||
certMsg := &certificateMsg13{
|
certMsg := &certificateMsg13{
|
||||||
certificates: hs.cert.Certificate,
|
certificates: hs.cert.Certificate,
|
||||||
}
|
}
|
||||||
@ -112,7 +187,7 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toSign := prepareDigitallySigned(sigHash, "TLS 1.3, server CertificateVerify", hs.finishedHash.Sum())
|
toSign := prepareDigitallySigned(sigHash, "TLS 1.3, server CertificateVerify", hs.finishedHash.Sum())
|
||||||
signature, err := hs.cert.PrivateKey.(crypto.Signer).Sign(config.rand(), toSign[:], opts)
|
signature, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), toSign[:], opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sendAlert(alertInternalError)
|
c.sendAlert(alertInternalError)
|
||||||
return err
|
return err
|
||||||
@ -128,58 +203,6 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
serverFinishedKey := hkdfExpandLabel(hash, sHandshakeTS, nil, "finished", hashSize)
|
|
||||||
clientFinishedKey := hkdfExpandLabel(hash, cHandshakeTS, nil, "finished", hashSize)
|
|
||||||
|
|
||||||
h := hmac.New(hash.New, serverFinishedKey)
|
|
||||||
h.Write(hs.finishedHash.Sum())
|
|
||||||
verifyData := h.Sum(nil)
|
|
||||||
serverFinished := &finishedMsg{
|
|
||||||
verifyData: verifyData,
|
|
||||||
}
|
|
||||||
hs.finishedHash.Write(serverFinished.marshal())
|
|
||||||
if _, err := c.writeRecord(recordTypeHandshake, serverFinished.marshal()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := c.flush(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
msg, err := c.readHandshake()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
clientFinished, ok := msg.(*finishedMsg)
|
|
||||||
if !ok {
|
|
||||||
c.sendAlert(alertUnexpectedMessage)
|
|
||||||
return unexpectedMessageError(clientFinished, msg)
|
|
||||||
}
|
|
||||||
h = hmac.New(hash.New, clientFinishedKey)
|
|
||||||
h.Write(hs.finishedHash.Sum())
|
|
||||||
expectedVerifyData := h.Sum(nil)
|
|
||||||
if len(expectedVerifyData) != len(clientFinished.verifyData) ||
|
|
||||||
subtle.ConstantTimeCompare(expectedVerifyData, clientFinished.verifyData) != 1 {
|
|
||||||
c.sendAlert(alertHandshakeFailure)
|
|
||||||
return errors.New("tls: client's Finished message is incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
masterSecret := hkdfExtract(hash, nil, handshakeSecret)
|
|
||||||
handshakeCtx = hs.finishedHash.Sum()
|
|
||||||
|
|
||||||
cTrafficSecret0 := hkdfExpandLabel(hash, masterSecret, handshakeCtx, "client application traffic secret", hashSize)
|
|
||||||
cKey = hkdfExpandLabel(hash, cTrafficSecret0, nil, "key", hs.suite.keyLen)
|
|
||||||
cIV = hkdfExpandLabel(hash, cTrafficSecret0, nil, "iv", 12)
|
|
||||||
sTrafficSecret0 := hkdfExpandLabel(hash, masterSecret, handshakeCtx, "server application traffic secret", hashSize)
|
|
||||||
sKey = hkdfExpandLabel(hash, sTrafficSecret0, nil, "key", hs.suite.keyLen)
|
|
||||||
sIV = hkdfExpandLabel(hash, sTrafficSecret0, nil, "iv", 12)
|
|
||||||
|
|
||||||
clientCipher = hs.suite.aead(cKey, cIV)
|
|
||||||
c.in.setCipher(c.vers, clientCipher)
|
|
||||||
serverCipher = hs.suite.aead(sKey, sIV)
|
|
||||||
c.out.setCipher(c.vers, serverCipher)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,6 +361,121 @@ func hkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L
|
|||||||
return hkdfExpand(hash, secret, hkdfLabel, L)
|
return hkdfExpand(hash, secret, hkdfLabel, L)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maximum allowed mismatch between the stated age of a ticket
|
||||||
|
// and the server-observed one. See
|
||||||
|
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8.2.
|
||||||
|
const ticketAgeSkewAllowance = 10 * time.Second
|
||||||
|
|
||||||
|
func (hs *serverHandshakeState) checkPSK(hash crypto.Hash) (earlySecret []byte, ok bool) {
|
||||||
|
if hs.c.config.SessionTicketsDisabled {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
foundDHE := false
|
||||||
|
for _, mode := range hs.clientHello.pskKeyExchangeModes {
|
||||||
|
if mode == pskDHEKeyExchange {
|
||||||
|
foundDHE = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundDHE {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
hashSize := hash.Size()
|
||||||
|
for i := range hs.clientHello.psks {
|
||||||
|
sessionTicket := append([]uint8{}, hs.clientHello.psks[i].identity...)
|
||||||
|
serializedTicket, _ := hs.c.decryptTicket(sessionTicket)
|
||||||
|
if serializedTicket == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s := &sessionState13{}
|
||||||
|
if ok := s.unmarshal(serializedTicket); !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.vers != hs.c.vers {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
clientAge := time.Duration(hs.clientHello.psks[i].obfTicketAge-s.ageAdd) * time.Millisecond
|
||||||
|
serverAge := time.Since(time.Unix(int64(s.createdAt), 0))
|
||||||
|
if clientAge-serverAge > ticketAgeSkewAllowance || clientAge-serverAge < -ticketAgeSkewAllowance {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.hash != uint16(hash) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
earlySecret := hkdfExtract(hash, s.resumptionSecret, nil)
|
||||||
|
handshakeCtx := hash.New().Sum(nil)
|
||||||
|
binderKey := hkdfExpandLabel(hash, earlySecret, handshakeCtx, "resumption psk binder key", hashSize)
|
||||||
|
binderFinishedKey := hkdfExpandLabel(hash, binderKey, nil, "finished", hashSize)
|
||||||
|
chHash := hash.New()
|
||||||
|
chHash.Write(hs.clientHello.rawTruncated)
|
||||||
|
h := hmac.New(hash.New, binderFinishedKey)
|
||||||
|
h.Write(chHash.Sum(nil))
|
||||||
|
expectedBinder := h.Sum(nil)
|
||||||
|
|
||||||
|
if subtle.ConstantTimeCompare(expectedBinder, hs.clientHello.psks[i].binder) == 1 {
|
||||||
|
hs.hello13.psk = true
|
||||||
|
hs.hello13.pskIdentity = uint16(i)
|
||||||
|
return earlySecret, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs *serverHandshakeState) sendSessionTicket13(hash crypto.Hash) error {
|
||||||
|
c := hs.c
|
||||||
|
if c.config.SessionTicketsDisabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
foundDHE := false
|
||||||
|
for _, mode := range hs.clientHello.pskKeyExchangeModes {
|
||||||
|
if mode == pskDHEKeyExchange {
|
||||||
|
foundDHE = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundDHE {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
handshakeCtx := hs.finishedHash.Sum()
|
||||||
|
resumptionSecret := hkdfExpandLabel(hash, hs.masterSecret, handshakeCtx, "resumption master secret", hash.Size())
|
||||||
|
|
||||||
|
ageAddBuf := make([]byte, 4)
|
||||||
|
if _, err := io.ReadFull(c.config.rand(), ageAddBuf); err != nil {
|
||||||
|
c.sendAlert(alertInternalError)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sessionState := &sessionState13{
|
||||||
|
vers: c.vers,
|
||||||
|
hash: uint16(hash),
|
||||||
|
ageAdd: uint32(ageAddBuf[0])<<24 | uint32(ageAddBuf[1])<<16 |
|
||||||
|
uint32(ageAddBuf[2])<<8 | uint32(ageAddBuf[3]),
|
||||||
|
createdAt: uint64(time.Now().Unix()),
|
||||||
|
resumptionSecret: resumptionSecret,
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket, err := c.encryptTicket(sessionState.marshal())
|
||||||
|
if err != nil {
|
||||||
|
c.sendAlert(alertInternalError)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ticketMsg := &newSessionTicketMsg13{
|
||||||
|
lifetime: 21600, // TODO(filippo)
|
||||||
|
ageAdd: sessionState.ageAdd,
|
||||||
|
ticket: ticket,
|
||||||
|
}
|
||||||
|
if _, err := c.writeRecord(recordTypeHandshake, ticketMsg.marshal()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// QuietError is an error wrapper that prevents the verbose handshake log
|
// QuietError is an error wrapper that prevents the verbose handshake log
|
||||||
// dump on errors. Exposed for use by GetCertificate.
|
// dump on errors. Exposed for use by GetCertificate.
|
||||||
type QuietError struct {
|
type QuietError struct {
|
||||||
|
@ -10,14 +10,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
sessionCache := runner.NewLRUClientSessionCache(10)
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
DialTLS: func(network, addr string) (net.Conn, error) {
|
DialTLS: func(network, addr string) (net.Conn, error) {
|
||||||
return runner.Dial(network, addr, &runner.Config{
|
return runner.Dial(network, addr, &runner.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
|
ClientSessionCache: sessionCache,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
DisableKeepAlives: true,
|
||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
|
|
||||||
resp, err := client.Get("https://" + os.Args[1])
|
resp, err := client.Get("https://" + os.Args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -25,4 +29,13 @@ func main() {
|
|||||||
if err := resp.Write(os.Stdout); err != nil {
|
if err := resp.Write(os.Stdout); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resumption
|
||||||
|
resp, err = client.Get("https://" + os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := resp.Write(os.Stdout); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
/boringssl/build/tool/bssl client -grease -min-version tls1.3 -max-version tls1.3 \
|
||||||
|
-session-out /session -connect "$@" < /httpreq.txt
|
||||||
|
exec /boringssl/build/tool/bssl client -grease -min-version tls1.3 -max-version tls1.3 \
|
||||||
|
-session-in /session -connect "$@" < /httpreq.txt
|
||||||
|
|
||||||
exec /boringssl/build/tool/bssl s_client -min-version tls1.3 -max-version tls1.3 -connect "$@" < /httpreq.txt
|
|
||||||
|
@ -11,7 +11,8 @@ if [ "$1" = "INSTALL" ]; then
|
|||||||
|
|
||||||
elif [ "$1" = "RUN" ]; then
|
elif [ "$1" = "RUN" ]; then
|
||||||
IP=$(docker inspect -f '{{ .NetworkSettings.IPAddress }}' tris-localserver)
|
IP=$(docker inspect -f '{{ .NetworkSettings.IPAddress }}' tris-localserver)
|
||||||
docker run -i --rm tls-tris:$2 $IP:$3 | tee output.txt
|
docker run --rm tls-tris:$2 $IP:$3 | tee output.txt
|
||||||
grep "Hello TLS 1.3" output.txt
|
grep "Hello TLS 1.3" output.txt | grep -v "resumed"
|
||||||
|
grep "Hello TLS 1.3" output.txt | grep "resumed"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
@ -14,8 +14,10 @@ func main() {
|
|||||||
DialTLS: func(network, addr string) (net.Conn, error) {
|
DialTLS: func(network, addr string) (net.Conn, error) {
|
||||||
return mint.Dial(network, addr, nil)
|
return mint.Dial(network, addr, nil)
|
||||||
},
|
},
|
||||||
|
DisableKeepAlives: true,
|
||||||
}
|
}
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
|
|
||||||
resp, err := client.Get("https://" + os.Args[1])
|
resp, err := client.Get("https://" + os.Args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -23,4 +25,13 @@ func main() {
|
|||||||
if err := resp.Write(os.Stdout); err != nil {
|
if err := resp.Write(os.Stdout); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resumption
|
||||||
|
resp, err = client.Get("https://" + os.Args[1])
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := resp.Write(os.Stdout); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
FROM scratch
|
FROM scratch
|
||||||
|
|
||||||
# GOOS=linux ../go.sh build -v -i .
|
|
||||||
ADD tris-localserver ./
|
|
||||||
|
|
||||||
ENV TLSDEBUG error
|
ENV TLSDEBUG error
|
||||||
|
|
||||||
EXPOSE 443
|
EXPOSE 443
|
||||||
EXPOSE 4443
|
EXPOSE 4443
|
||||||
|
|
||||||
|
# GOOS=linux ../go.sh build -v -i .
|
||||||
|
ADD tris-localserver ./
|
||||||
|
|
||||||
CMD [ "./tris-localserver", "0.0.0.0:443", "0.0.0.0:4443" ]
|
CMD [ "./tris-localserver", "0.0.0.0:443", "0.0.0.0:4443" ]
|
||||||
|
@ -19,7 +19,11 @@ var tlsVersionToName = map[uint16]string{
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "<!DOCTYPE html><p>Hello TLS %s _o/\n", tlsVersionToName[r.TLS.Version])
|
resumed := ""
|
||||||
|
if r.TLS.DidResume {
|
||||||
|
resumed = " [resumed]"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "<!DOCTYPE html><p>Hello TLS %s%s _o/\n", tlsVersionToName[r.TLS.Version], resumed)
|
||||||
})
|
})
|
||||||
|
|
||||||
http.HandleFunc("/ch", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/ch", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -15,7 +15,10 @@ ENV USE_64=1 NSS_ENABLE_TLS_1_3=1
|
|||||||
# ARG REVISION=3e7b53b18112
|
# ARG REVISION=3e7b53b18112
|
||||||
|
|
||||||
# Draft 18
|
# Draft 18
|
||||||
ARG REVISION=b6dfef6d0ff0
|
# ARG REVISION=b6dfef6d0ff0
|
||||||
|
|
||||||
|
# tstclnt resumption
|
||||||
|
ARG REVISION=460a0a1e009f
|
||||||
|
|
||||||
RUN cd nss && hg pull
|
RUN cd nss && hg pull
|
||||||
RUN cd nss && hg checkout -C $REVISION
|
RUN cd nss && hg checkout -C $REVISION
|
||||||
|
@ -5,4 +5,4 @@ shift
|
|||||||
HOST="${ADDR[0]}"
|
HOST="${ADDR[0]}"
|
||||||
PORT="${ADDR[1]}"
|
PORT="${ADDR[1]}"
|
||||||
|
|
||||||
exec /dist/OBJ-PATH/bin/tstclnt -D -V tls1.3:tls1.3 -o -O -h $HOST -p $PORT -v "$@" < /httpreq.txt
|
exec /dist/OBJ-PATH/bin/tstclnt -D -V tls1.3:tls1.3 -o -O -h $HOST -p $PORT -v -A /httpreq.txt -L 2 "$@"
|
||||||
|
@ -278,7 +278,7 @@ Curves:
|
|||||||
hs.hello.scts = hs.cert.SignedCertificateTimestamps
|
hs.hello.scts = hs.cert.SignedCertificateTimestamps
|
||||||
}
|
}
|
||||||
|
|
||||||
if committer, ok := c.conn.(Committer); ok {
|
if committer, ok := c.conn.(Committer); ok { // TODO: probably committing too early
|
||||||
err = committer.Commit()
|
err = committer.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -353,9 +353,10 @@ func (hs *serverHandshakeState) checkForResumption() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var ok bool
|
sessionTicket := append([]uint8{}, hs.clientHello.sessionTicket...)
|
||||||
var sessionTicket = append([]uint8{}, hs.clientHello.sessionTicket...)
|
serializedState, usedOldKey := c.decryptTicket(sessionTicket)
|
||||||
if hs.sessionState, ok = c.decryptTicket(sessionTicket); !ok {
|
hs.sessionState = &sessionState{usedOldKey: usedOldKey}
|
||||||
|
if ok := hs.sessionState.unmarshal(serializedState); !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,7 +731,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
|
|||||||
masterSecret: hs.masterSecret,
|
masterSecret: hs.masterSecret,
|
||||||
certificates: hs.certsFromClient,
|
certificates: hs.certsFromClient,
|
||||||
}
|
}
|
||||||
m.ticket, err = c.encryptTicket(&state)
|
m.ticket, err = c.encryptTicket(state.marshal())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -193,8 +193,7 @@ func (s *sessionState13) unmarshal(data []byte) bool {
|
|||||||
return int(l) == len(s.resumptionSecret)
|
return int(l) == len(s.resumptionSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
|
func (c *Conn) encryptTicket(serialized []byte) ([]byte, error) {
|
||||||
serialized := state.marshal()
|
|
||||||
encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size)
|
encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size)
|
||||||
keyName := encrypted[:ticketKeyNameLen]
|
keyName := encrypted[:ticketKeyNameLen]
|
||||||
iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
|
iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
|
||||||
@ -218,7 +217,7 @@ func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
|
|||||||
return encrypted, nil
|
return encrypted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
|
func (c *Conn) decryptTicket(encrypted []byte) (serialized []byte, usedOldKey bool) {
|
||||||
if c.config.SessionTicketsDisabled ||
|
if c.config.SessionTicketsDisabled ||
|
||||||
len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
|
len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
|
||||||
return nil, false
|
return nil, false
|
||||||
@ -258,7 +257,5 @@ func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
|
|||||||
plaintext := ciphertext
|
plaintext := ciphertext
|
||||||
cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
|
cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
|
||||||
|
|
||||||
state := &sessionState{usedOldKey: keyIndex > 0}
|
return plaintext, keyIndex > 0
|
||||||
ok := state.unmarshal(plaintext)
|
|
||||||
return state, ok
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user