Porovnat revize

...

26 Revize

Autor SHA1 Zpráva Datum
  Kris Kwiatkowski 69c276c627 test: check if tris and bssl can still connect without qr před 6 roky
  Kris Kwiatkowski 2411297a28 adds SIDH to interoperability tests (tris-tris) před 6 roky
  Henry D. Case c02cc0e83a Adds SIDH751-X448 support před 6 roky
  Henry D. Case 44d58d9e5c Change IDs for hybrid key exchange před 6 roky
  Henry D. Case aedcb7cf3c Sets curve ID established during TLS 1.3 handshake před 6 roky
  Henry D. Case 4386d89c02 Introduces crypto_catalog před 6 roky
  Henry D. Case 736ba21160 use NOBS_REPO from env if defined před 6 roky
  Henry D. Case 35ba04f0a1 Works před 6 roky
  Henry D. Case 0f8234a803 temporary: adds swap_tls target před 6 roky
  Henry D. Case 772c98f5ed vendors nobs-crypto in go-crypto před 6 roky
  Henry D. Case f3d880878e SIDH: Init před 6 roky
  Kris Kwiatkowski 49bb3bdab8 refactoring of the tris test client před 6 roky
  Kris Kwiatkowski d7f149b717 refactoring of the tris test server před 6 roky
  Henry D. Case 031d89f0fb refactors record encryption code před 6 roky
  Henry Case 8d3ff2b07d server must NOT send version prior to TLS1.3 in supported_versions (#119) před 6 roky
  Henry D. Case 905048a9b0 Use binary interface to encode in big-endian před 6 roky
  Henry Case 0caaafafe3 tls13: adds additional data to AEAD (#114) před 6 roky
  Henry D. Case 3ff71dcdc5 tests: enable client authentication in bogo před 6 roky
  Henry D. Case 6e4abe2d07 TLSv1.3 draft-23: align tests před 6 roky
  Henry D. Case 03138ec18e TLSv1.3 -draft23: Implementation of signature_algorithms_cert před 6 roky
  Henry D. Case 5bdf1af124 TLS1.3 -draft23: Renumber key_share před 6 roky
  Evan Klitzke 67bc308e04 Update client SCT list during TLS 1.3 handshake, fixes #76 před 6 roky
  Henry D. Case b1d6c0aeaa Change function name verifyPeerCertificate->verifyPeerHandshakeSignature před 6 roky
  Henry D. Case 91d6db578b CI: Fail build if code is wrongly formatted před 6 roky
  Henry D. Case b6af4dd343 Code formatting for handshake_server_test.go před 6 roky
  Henry D. Case 3f720fc50c Code formatting for TRIS test client and server před 6 roky
26 změnil soubory, kde provedl 1233 přidání a 262 odebrání
  1. +3
    -0
      .travis.yml
  2. +201
    -11
      13.go
  3. +3
    -2
      README.md
  4. +21
    -2
      _dev/Makefile
  5. +14
    -5
      _dev/bogo/Dockerfile
  6. +13
    -4
      _dev/boring/Dockerfile
  7. +2
    -2
      _dev/boring/run.sh
  8. +3
    -3
      _dev/boring/server.sh
  9. +4
    -0
      _dev/crypto_catalog/Makefile
  10. +239
    -0
      _dev/crypto_catalog/client.go
  11. +274
    -0
      _dev/crypto_catalog/server.go
  12. +41
    -14
      _dev/interop_test_runner
  13. +1
    -0
      _dev/tris-localserver/Dockerfile
  14. +1
    -0
      _dev/tris-localserver/runner.sh
  15. +68
    -59
      _dev/tris-localserver/server.go
  16. +95
    -39
      _dev/tris-testclient/client.go
  17. +7
    -1
      _dev/tstclnt/Dockerfile
  18. +20
    -0
      _dev/utils/fmtcheck.sh
  19. +27
    -0
      _dev/utils/pre-commit
  20. +12
    -1
      cipher_suites.go
  21. +29
    -19
      common.go
  22. +28
    -14
      conn.go
  23. +4
    -4
      example_test.go
  24. +2
    -1
      handshake_client.go
  25. +117
    -75
      handshake_messages.go
  26. +4
    -6
      handshake_server_test.go

+ 3
- 0
.travis.yml Zobrazit soubor

@@ -15,6 +15,9 @@ env:
matrix:
fast_finish: true

before_install:
- make -f _dev/Makefile fmtcheck

install:
- sudo pip install docker



+ 201
- 11
13.go Zobrazit soubor

@@ -21,6 +21,8 @@ import (
"sync/atomic"
"time"

sidh "github_com/henrydcase/nobs/dh/sidh"
x448 "github_com/henrydcase/nobs/ec/x448"
"golang_org/x/crypto/curve25519"
)

@@ -40,6 +42,21 @@ const (
secretResumption
)

// OZAPTF: better index by AlgID
const (
x25519SharedSecretSize = 32
P751PubKeySize = 564
P751PrvKeySize = 48
P751SharedSecretSize = 188
SidhP751Curve25519PubKeySize = x25519SharedSecretSize + P751PubKeySize
SidhP751Curve25519PrvKeySize = x25519SharedSecretSize + P751PrvKeySize
SidhP751Curve25519SharedKeySize = x25519SharedSecretSize + P751SharedSecretSize

SidhP751Curve448PubKeySize = x448.SharedSecretSize + P751PubKeySize
SidhP751Curve448PrvKeySize = x448.SharedSecretSize + P751PrvKeySize
SidhP751Curve448SharedKeySize = x448.SharedSecretSize + P751SharedSecretSize
)

type keySchedule13 struct {
suite *cipherSuite
transcriptHash hash.Hash // uses the cipher suite hash algo
@@ -49,6 +66,23 @@ type keySchedule13 struct {
config *Config // Used for KeyLogWriter callback, nil if keylogging is disabled.
}

type Role uint8

const (
kRole_Server = iota
kRole_Client
)

// OZAPTF: comment
// Depending on role returns pair of key variant to be used by
// local and remote process.
func getSidhKeyVariant(r Role) (sidh.KeyVariant, sidh.KeyVariant) {
if r == kRole_Client {
return sidh.KeyVariant_SIDH_A, sidh.KeyVariant_SIDH_B
}
return sidh.KeyVariant_SIDH_B, sidh.KeyVariant_SIDH_A
}

func newKeySchedule13(suite *cipherSuite, config *Config, clientRandom []byte) *keySchedule13 {
if config.KeyLogWriter == nil {
clientRandom = nil
@@ -158,12 +192,13 @@ CurvePreferenceLoop:
}
}

privateKey, serverKS, err := config.generateKeyShare(ks.group)
privateKey, serverKS, err := config.generateKeyShare(ks.group, kRole_Server)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
hs.hello.keyShare = serverKS
c.KeyShareCurve = serverKS.group

hash := hashForSuite(hs.suite)
hashSize := hash.Size()
@@ -186,7 +221,7 @@ CurvePreferenceLoop:

earlyClientCipher, _ := hs.keySchedule.prepareCipher(secretEarlyClient)

ecdheSecret := deriveECDHESecret(ks, privateKey)
ecdheSecret := deriveECDHESecret(ks, privateKey, kRole_Server)
if ecdheSecret == nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: bad ECDHE client share")
@@ -225,6 +260,7 @@ CurvePreferenceLoop:
certReq := new(certificateRequestMsg13)
// extension 'signature_algorithms' MUST be specified
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
certReq.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
hs.keySchedule.write(certReq.marshal())
if _, err := hs.c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
return err
@@ -328,7 +364,7 @@ func (hs *serverHandshakeState) readClientFinished13(hasConfirmLock bool) error
return unexpectedMessageError(certVerify, msg)
}

err, alertCode := verifyPeerCertificate(
err, alertCode := verifyPeerHandshakeSignature(
certVerify,
pubKey,
supportedSignatureAlgorithms13,
@@ -540,9 +576,12 @@ func prepareDigitallySigned(hash crypto.Hash, context string, data []byte) []byt
return h.Sum(nil)
}

func (c *Config) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
// generateKeyShare generates keypair. Private key is returned as first argument, public key
// is returned in keyShare.data. keyshare.curveID stores ID of the scheme used.
func (c *Config) generateKeyShare(curveID CurveID, role Role) ([]byte, keyShare, error) {
// OZAPTF: refactor
if curveID == X25519 {
var scalar, public [32]byte
var scalar, public [x25519SharedSecretSize]byte
if _, err := io.ReadFull(c.rand(), scalar[:]); err != nil {
return nil, keyShare{}, err
}
@@ -551,6 +590,69 @@ func (c *Config) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
return scalar[:], keyShare{group: curveID, data: public[:]}, nil
}

if curveID == SidhP751Curve25519 {
var public25519 [x25519SharedSecretSize]byte
var secret25519 [x25519SharedSecretSize]byte
var public [SidhP751Curve25519PubKeySize]byte
var secret [SidhP751Curve25519PrvKeySize]byte
var variant, _ = getSidhKeyVariant(role)
var prvKey = sidh.NewPrivateKey(sidh.FP_751, variant)

if _, err := io.ReadFull(c.rand(), secret25519[:]); err != nil {
return nil, keyShare{}, err
}

curve25519.ScalarBaseMult(&public25519, &secret25519)

if prvKey.Generate(c.rand()) != nil {
return nil, keyShare{}, errors.New("tls: private SIDH key generation failed")
}
pubKey, err := sidh.GeneratePublicKey(prvKey)
if err != nil {
return nil, keyShare{}, errors.New("tls: public SIDH key generation failed")
}

// Hybrid "shared key" = X25519 || P751
// OZAPTF SIZE-len
copy(public[:], pubKey.Export())
copy(public[P751PubKeySize:], public25519[:])
copy(secret[:], prvKey.Export())
copy(secret[P751PrvKeySize:], secret25519[:])
return secret[:], keyShare{group: curveID, data: public[:]}, nil
}

if curveID == SidhP751Curve448 {
var public448 [x448.SharedSecretSize]byte
var secret448 [x448.SharedSecretSize]byte
var public [SidhP751Curve448PubKeySize]byte
var secret [SidhP751Curve448PrvKeySize]byte
var variant, _ = getSidhKeyVariant(role)
var prvKey = sidh.NewPrivateKey(sidh.FP_751, variant)

if _, err := io.ReadFull(c.rand(), secret448[:]); err != nil {
return nil, keyShare{}, err
}

x448.ScalarBaseMult(&public448, &secret448)

if prvKey.Generate(c.rand()) != nil {
return nil, keyShare{}, errors.New("tls: private SIDH key generation failed")
}
pubKey, err := sidh.GeneratePublicKey(prvKey)
if err != nil {
return nil, keyShare{}, errors.New("tls: public SIDH key generation failed")
}

// Hybrid "shared key" = X448 || P751
// OZAPTF SIZE-len
copy(public[:], pubKey.Export())
copy(public[P751PubKeySize:], public448[:])
copy(secret[:], prvKey.Export())
copy(secret[P751PrvKeySize:], secret448[:])
return secret[:], keyShare{group: curveID, data: public[:]}, nil
}

// else...
curve, ok := curveForCurveID(curveID)
if !ok {
return nil, keyShare{}, errors.New("tls: preferredCurves includes unsupported curve")
@@ -565,19 +667,93 @@ func (c *Config) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
return privateKey, keyShare{group: curveID, data: ecdhePublic}, nil
}

func deriveECDHESecret(ks keyShare, secretKey []byte) []byte {
func deriveECDHESecret(ks keyShare, secretKey []byte, role Role) []byte {
if ks.group == X25519 {
if len(ks.data) != 32 {
if len(ks.data) != x25519SharedSecretSize {
return nil
}

var theirPublic, sharedKey, scalar [32]byte
var theirPublic, sharedKey, scalar [x25519SharedSecretSize]byte
copy(theirPublic[:], ks.data)
copy(scalar[:], secretKey)
curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
return sharedKey[:]
}

if ks.group == SidhP751Curve25519 {
var prvVariant, pubVariant = getSidhKeyVariant(role)
var sharedKey [SidhP751Curve25519SharedKeySize]byte
var pubX25519, prvX25519, sharedKeyX25519 [x25519SharedSecretSize]byte

if len(ks.data) != SidhP751Curve25519PubKeySize {
return nil
}
if len(secretKey) != SidhP751Curve25519PrvKeySize {
return nil
}

prvKey := sidh.NewPrivateKey(sidh.FP_751, prvVariant)
pubKey := sidh.NewPublicKey(sidh.FP_751, pubVariant)

if err := prvKey.Import(secretKey[:P751PrvKeySize]); err != nil {
return nil
}
if err := pubKey.Import(ks.data[:P751PubKeySize]); err != nil {
return nil
}
sharedSidhKey, err := sidh.DeriveSecret(prvKey, pubKey)
if err != nil {
return nil
}

// OZAPTF: same thing for x25519
copy(prvX25519[:], secretKey[P751PrvKeySize:])
copy(pubX25519[:], ks.data[P751PubKeySize:])
curve25519.ScalarMult(&sharedKeyX25519, &prvX25519, &pubX25519)

// format shared key
copy(sharedKey[:], sharedSidhKey)
copy(sharedKey[P751SharedSecretSize:], sharedKeyX25519[:])
return sharedKey[:]
}

if ks.group == SidhP751Curve448 {
var prvVariant, pubVariant = getSidhKeyVariant(role)
var sharedKey [SidhP751Curve448SharedKeySize]byte
var pubX448, prvX448, sharedKeyX448 [x448.SharedSecretSize]byte

if len(ks.data) != SidhP751Curve448PubKeySize {
return nil
}
if len(secretKey) != SidhP751Curve448PrvKeySize {
return nil
}

prvKey := sidh.NewPrivateKey(sidh.FP_751, prvVariant)
pubKey := sidh.NewPublicKey(sidh.FP_751, pubVariant)

if err := prvKey.Import(secretKey[:P751PrvKeySize]); err != nil {
return nil
}
if err := pubKey.Import(ks.data[:P751PubKeySize]); err != nil {
return nil
}
sharedSidhKey, err := sidh.DeriveSecret(prvKey, pubKey)
if err != nil {
return nil
}

// OZAPTF: same thing for x25519
copy(prvX448[:], secretKey[P751PrvKeySize:])
copy(pubX448[:], ks.data[P751PubKeySize:])
x448.ScalarMult(&sharedKeyX448, &prvX448, &pubX448)

// format shared key
copy(sharedKey[:], sharedSidhKey)
copy(sharedKey[P751SharedSecretSize:], sharedKeyX448[:])
return sharedKey[:]
}

curve, ok := curveForCurveID(ks.group)
if !ok {
return nil
@@ -841,7 +1017,7 @@ func (hs *clientHandshakeState) processEncryptedExtensions(ee *encryptedExtensio
return nil
}

func verifyPeerCertificate(
func verifyPeerHandshakeSignature(
certVerify *certificateVerifyMsg,
pubKey crypto.PublicKey,
signAlgosKnown []SignatureScheme,
@@ -953,6 +1129,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
hash := hashForSuite(hs.suite)
hashSize := hash.Size()
serverHello := hs.serverHello
c.scts = serverHello.scts

// middlebox compatibility mode, send CCS before second flight.
if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
@@ -969,7 +1146,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {

// 0-RTT is not supported yet, so use an empty PSK.
hs.keySchedule.setSecret(nil)
ecdheSecret := deriveECDHESecret(serverHello.keyShare, hs.privateKey)
ecdheSecret := deriveECDHESecret(serverHello.keyShare, hs.privateKey, kRole_Client)
if ecdheSecret == nil {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: bad ECDHE server share")
@@ -1048,7 +1225,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certVerifyMsg, msg)
}
err, alertCode := verifyPeerCertificate(
err, alertCode := verifyPeerHandshakeSignature(
certVerifyMsg,
hs.c.peerCertificates[0].PublicKey,
hs.hello.supportedSignatureAlgorithms,
@@ -1111,5 +1288,18 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
return errors.New("tls: unexpected data after handshake")
}
c.in.setCipher(c.vers, appServerCipher)
c.KeyShareCurve = clientKS.group
return nil
}

// supportedSigAlgorithmsCert iterates over schemes and filters out those algorithms
// which are not supported for certificate verification.
func supportedSigAlgorithmsCert(schemes []SignatureScheme) (ret []SignatureScheme) {
for _, sig := range schemes {
// X509 doesn't support PSS signatures
if !signatureSchemeIsPSS(sig) {
ret = append(ret, sig)
}
}
return
}

+ 3
- 2
README.md Zobrazit soubor

@@ -61,7 +61,8 @@ There are number of things that need to be setup before running tests. Most impo

```
git clone https://github.com/cloudflare/tls-tris.git
cd tls-tris; make -f _dev/Makefile build-all
cd tls-tris; cp _dev/utils/pre-commit .git/hooks/
make -f _dev/Makefile build-all
```

### Testing
@@ -70,7 +71,7 @@ We run 3 kinds of test:.

* Unit testing: <br/>``make -f _dev/Makefile test-unit``
* Testing against BoringSSL test suite: <br/>``make -f _dev/Makefile test-bogo``
* Compatibility testing (see below):<br/>``make -f _dev/Makefile test-compat``
* Compatibility testing (see below):<br/>``make -f _dev/Makefile test-interop``

To run all the tests in one go use:
```


+ 21
- 2
_dev/Makefile Zobrazit soubor

@@ -8,6 +8,7 @@ BUILD_DIR ?= $(PRJ_DIR)/_dev/GOROOT
# Compiler
GO ?= go
DOCKER ?= docker
GIT ?= git

# Build environment
OS ?= $(shell $(GO) env GOHOSTOS)
@@ -18,14 +19,19 @@ GOROOT_ENV := $(shell $(GO) env GOROOT)
GOROOT_LOCAL = $(BUILD_DIR)/$(OS_ARCH)
# Flag indicates wheter invoke "go install -race std". Supported only on amd64 with CGO enabled
INSTALL_RACE:= $(words $(filter $(ARCH)_$(shell go env CGO_ENABLED), amd64_1))
TMP_DIR := $(shell mktemp -d)

# Test targets used for compatibility testing
TARGET_TEST_COMPAT=boring picotls tstclnt

# Some target-specific constants
BORINGSSL_REVISION=1530ef3e
BORINGSSL_REVISION=03de6813d8992a649092b4874ef0ebc022e2f58a
BOGO_DOCKER_TRIS_LOCATION=/go/src/github.com/cloudflare/tls-tris

# NOBS crypto
NOBS_REPO ?= https://github.com/henrydcase/nobscrypto.git


###############
#
# Build targets
@@ -48,13 +54,24 @@ $(BUILD_DIR)/$(OS_ARCH)/.ok_$(VER_OS_ARCH): clean
# Apply additional patches
for p in $(wildcard $(DEV_DIR)/patches/*); do patch -d "$(GOROOT_LOCAL)" -p1 < "$$p"; done

# Vendor nobs
$(GIT) clone $(NOBS_REPO) $(TMP_DIR)/nobs
cd $(TMP_DIR)/nobs; make vendor-sidh-for-tls
cp -rf $(TMP_DIR)/nobs/tls_vendor/* $(GOROOT_LOCAL)/src/vendor/

# Create go package
GOARCH=$(ARCH) GOROOT="$(GOROOT_LOCAL)" $(GO) install -v std
ifeq ($(INSTALL_RACE),1)
GOARCH=$(ARCH) GOROOT="$(GOROOT_LOCAL)" $(GO) install -race -v std
endif
rm -rf $(TMP_DIR)
@touch "$@"

# Swap TLS implementation
swap_tls:
rm -r $(GOROOT_LOCAL)/src/crypto/tls/*
rsync -rltgoD $(PRJ_DIR)/ $(GOROOT_LOCAL)/src/crypto/tls/ --exclude=$(lastword $(subst /, ,$(DEV_DIR)))

build-test-%: $(BUILD_DIR)/$(OS_ARCH)/.ok_$(VER_OS_ARCH)
$(DOCKER) build $(BUILDARG) -t tls-tris:$* $(DEV_DIR)/$*
$(DOCKER) build $(BUILDARG) -t $(*)-localserver $(DEV_DIR)/$*
@@ -112,5 +129,7 @@ clean:
clean-all: clean
rm -rf $(BUILD_DIR)

fmtcheck:
$(DEV_DIR)/utils/fmtcheck.sh

.PHONY: $(BUILD_DIR) clean build build-test test test-unit test-bogo test-compat
.PHONY: $(BUILD_DIR) clean build build-test test test-unit test-bogo test-interop

+ 14
- 5
_dev/bogo/Dockerfile Zobrazit soubor

@@ -10,8 +10,8 @@ RUN apk add --update \

ENV CGO_ENABLED=0

RUN git clone https://github.com/FiloSottile/crypto-tls-bogo-shim \
/go/src/github.com/FiloSottile/crypto-tls-bogo-shim
RUN git clone https://github.com/henrydcase/crypto-tls-bogo-shim \
/go/src/github.com/henrydcase/crypto-tls-bogo-shim

# Draft 18 with client-tests branch
#ARG REVISION=3f5e87d6a1931b6f6930e4eadb7b2d0b2aa7c588
@@ -20,10 +20,19 @@ RUN git clone https://github.com/FiloSottile/crypto-tls-bogo-shim \
#ARG REVISION=81cc32b846c9fe2ea32613287e57a6a0db7bbb9a

# Draft 22 with draft22-client branch (client-tests + draft22)
ARG REVISION=f9729b5e4eafb1f1d313949388c3c2b167e84734
# ARG REVISION=f9729b5e4eafb1f1d313949388c3c2b167e84734

RUN cd /go/src/github.com/FiloSottile/crypto-tls-bogo-shim && \
# Draft 23
#ARG REVISION=d07b9e80a87c871c2569ce4aabd06695336c5dc5

# Draft 23 (+ client authentication)
# ARG REVISION=cd33ad248ae9490854f0077ca046b47cac3735bf

# Draft 28
ARG REVISION=33204d1eaa497819c6325998d7ba6b66316790f3

RUN cd /go/src/github.com/henrydcase/crypto-tls-bogo-shim && \
git checkout $REVISION

WORKDIR /go/src/github.com/FiloSottile/crypto-tls-bogo-shim
WORKDIR /go/src/github.com/henrydcase/crypto-tls-bogo-shim
CMD ["make", "run"]

+ 13
- 4
_dev/boring/Dockerfile Zobrazit soubor

@@ -34,15 +34,24 @@ RUN mkdir boringssl/build
# ARG REVISION=89917a5

# Draft 18
#ARG REVISION=9b885c5
# ARG REVISION=9b885c5
# Draft 18, but with "bssl server -loop -www" support and build fix
ARG REVISION=40b24c8154
# ARG REVISION=40b24c8154

# Draft 21
#ARG REVISION=cd8470f
# ARG REVISION=cd8470f

# Draft 22
ARG REVISION=1530ef3e
# ARG REVISION=1530ef3e

# Draft 23
# ARG REVISION=cb15cfda29c0c60d8d74145b17c93b43a7667837

# Draft 28
# ARG REVISION=861f384d7bc59241a9df1634ae938d8e75be2d30

# Latest
ARG REVISION=03de6813d8992a649092b4874ef0ebc022e2f58a

RUN cd boringssl && git fetch
RUN cd boringssl && git checkout $REVISION


+ 2
- 2
_dev/boring/run.sh Zobrazit soubor

@@ -2,7 +2,7 @@
set -e

/boringssl/build/tool/bssl client -grease -min-version tls1.3 -max-version tls1.3 \
-tls13-variant draft22 -session-out /session -connect "$@" < /httpreq.txt
-tls13-variant draft28 -session-out /session -connect "$@" < /httpreq.txt
exec /boringssl/build/tool/bssl client -grease -min-version tls1.3 -max-version tls1.3 \
-tls13-variant draft22 -session-in /session -connect "$@" < /httpreq.txt
-tls13-variant draft28 -session-in /session -connect "$@" < /httpreq.txt


+ 3
- 3
_dev/boring/server.sh Zobrazit soubor

@@ -6,21 +6,21 @@ set -x
bssl server \
-key rsa.pem \
-min-version tls1.2 -max-version tls1.3 \
-tls13-draft22-variant \
-tls13-variant draft28 \
-accept 1443 -loop -www 2>&1 &

# ECDSA
bssl server \
-key ecdsa.pem \
-min-version tls1.2 -max-version tls1.3 \
-tls13-draft22-variant \
-tls13-variant draft28 \
-accept 2443 -loop -www 2>&1 &

# Require client authentication (with ECDSA)
bssl server \
-key ecdsa.pem \
-min-version tls1.2 -max-version tls1.3 \
-tls13-draft22-variant \
-tls13-variant draft28 \
-accept 6443 -loop -www \
-require-any-client-cert -debug 2>&1 &



+ 4
- 0
_dev/crypto_catalog/Makefile Zobrazit soubor

@@ -0,0 +1,4 @@
all:
make -f ~/repos/tls-tris/_dev/Makefile swap_tls
GOROOT=../GOROOT/linux_amd64 go build client.go
GOROOT=../GOROOT/linux_amd64 go build server.go

+ 239
- 0
_dev/crypto_catalog/client.go Zobrazit soubor

@@ -0,0 +1,239 @@
package main

import (
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"io"
"log"
"os"
"strings"
)

var tlsVersionToName = map[uint16]string{
tls.VersionTLS10: "1.0",
tls.VersionTLS11: "1.1",
tls.VersionTLS12: "1.2",
tls.VersionTLS13: "1.3",
tls.VersionTLS13Draft18: "1.3 (draft 18)",
tls.VersionTLS13Draft23: "1.3 (draft 23)",
}

var cipherSuiteIdToName = map[uint16]string{
tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA",
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256",
tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384",
tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256",
tls.TLS_ECDHE_SIDH_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_SIDH_ECDSA_WITH_AES_128_GCM_SHA256",
}

type Client struct {
KeyLogWriter io.Writer
failed uint
client_cert tls.Certificate
client_certpool *x509.CertPool
preferedCurves []tls.CurveID
}

func (c *Client) run(addr string, version, cipherSuite uint16) {
tls_config := &tls.Config{
InsecureSkipVerify: true,
MinVersion: version,
MaxVersion: version,
CipherSuites: []uint16{cipherSuite},
KeyLogWriter: c.KeyLogWriter,
Certificates: []tls.Certificate{c.client_cert},
RootCAs: c.client_certpool,
CurvePreferences: c.preferedCurves,
}
con, err := tls.Dial("tcp", addr, tls_config)
if err != nil {
fmt.Printf("handshake failed: %v\n\n", err)
c.failed++
return
}
defer con.Close()

fmt.Printf("Established: TLS ver %X CipherSuite: %X CurveID %X\n",
con.ConnectionState().Version,
con.ConnectionState().CipherSuite,
con.KeyShareCurve)

_, err = con.Write([]byte("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"))
if err != nil {
fmt.Printf("Write failed: %v\n\n", err)
c.failed++
return
}

buf := make([]byte, 1024)
n, err := con.Read(buf)
// A non-zero read with EOF is acceptable and occurs when a close_notify
// is received right after reading data (observed with NSS selfserv).
if !(n > 0 && err == io.EOF) && err != nil {
fmt.Printf("Read failed: %v\n\n", err)
c.failed++
return
}
fmt.Printf("Read %d bytes\n", n)

fmt.Println("OK\n")
}

func main() {
var keylog_file, enable_sidh string
var enable_rsa, enable_ecdsa, client_auth bool

flag.StringVar(&keylog_file, "keylogfile", "", "Secrets will be logged here")
flag.BoolVar(&enable_rsa, "rsa", false, "Whether to enable RSA cipher suites")
flag.BoolVar(&enable_ecdsa, "ecdsa", false, "Whether to enable ECDSA cipher suites")
flag.BoolVar(&client_auth, "cliauth", false, "Whether to enable client authentication")
flag.StringVar(&enable_sidh, "sidh", "", "Whether to use SIDH. Argumens: X25519 or X448")
flag.Parse()
if flag.NArg() != 1 {
flag.Usage()
os.Exit(1)
}
addr := flag.Arg(0)
if !strings.Contains(addr, ":") {
addr += ":443"
}

client := Client{}
if keylog_file == "" {
keylog_file = os.Getenv("SSLKEYLOGFILE")
}
if keylog_file != "" {
keylog_writer, err := os.OpenFile(keylog_file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatalf("Cannot open keylog file: %v", err)
}
client.KeyLogWriter = keylog_writer
log.Println("Enabled keylog")
}

if client_auth {
var err error
client.client_cert, err = tls.X509KeyPair([]byte(client_crt), []byte(client_key))
if err != nil {
panic("Can't load client certificate")
}

client.client_certpool = x509.NewCertPool()
if !client.client_certpool.AppendCertsFromPEM([]byte(client_ca)) {
panic("Can't load client CA cert")
}
}

if enable_rsa {
// Sanity check: TLS 1.2 with the mandatory cipher suite from RFC 5246
client.run(addr, tls.VersionTLS12, tls.TLS_RSA_WITH_AES_128_CBC_SHA)
}
if enable_ecdsa {
// Sane cipher suite for TLS 1.2 with an ECDSA cert (as used by boringssl)
client.run(addr, tls.VersionTLS12, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
}

if enable_sidh != "" {
switch enable_sidh {
case "X25519":
client.preferedCurves = []tls.CurveID{tls.SidhP751Curve25519}
case "X448":
client.preferedCurves = []tls.CurveID{tls.SidhP751Curve448}
}
client.run(addr, tls.VersionTLS13, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
}

if client.failed > 0 {
log.Fatalf("Failed handshakes: %d\n", client.failed)
} else {
fmt.Println("All handshakes passed")
}
}

const (
client_ca = `-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIJAPpBgIvtQb1EMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgwMjEzMjAxNjA3WhcNMTkwMjEzMjAxNjA3WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAr4xgdmB4DaEh8zRFmg/1ZxYhQZMUP0iQX/Y8nDWxNlcd42p3TgpY1biz
jrq58ln9Om4U/GAn2RmtBAynSBXIlR5oVa44JeMM8Ka8R/dMKyHpF0Nj2EJB9unb
TC33PfzOlnKQxATwevnnhI6tGluWmwvxXUi7WnX0di+nQg9HrIVom3KrmRr2/41y
g497ccYUuNnKE6sewGdGzw045oWZpMDA2Us+MFo1IywOurjaM9bueRhPTcIiQ8RE
h7qb+FRwfxaj9ynZA2PCM7WMSSWCiZJV0uj/pshYF2lvtJcJef4dhwnsYBpc+mgx
2q9qcUBeo3ZHbi1/PRqjwSmcW3yY5cQRbpYp6xFmgmX3oHQkVXS0UlpNVZ+morcS
HEpaK8b76fCFcL5yFsAJkPPfny1IKU+CfaVq60dM/mxbEW6J4mZT/uAiqrCilMC+
FyiATCZur8Ks7p47eZy700DllLod7gWTiuZTgHeQFVoX+jxbCZKlFn5Xspu8ALoK
Mla/q83mICRVy3+eMUsD7DNvoWYpCAYy/oMk0VWfrQ48JkCGbBW2PW/dU2nmqVhY
/11rurkr+1TUvYodnajANtXvUjW1DPOLb4dES4Qc4b7Fw8eFXrARhl5mXiL5HFKR
/VnRshiJ+QwTVkxl+KkZHEm/WS8QD+Zd8leAxh9MCoaU/XrBUBkCAwEAAaNTMFEw
HQYDVR0OBBYEFKUinuD1xRvcNd2Wti/PnBJp7On1MB8GA1UdIwQYMBaAFKUinuD1
xRvcNd2Wti/PnBJp7On1MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
ggIBAJdJrNBftqkTs2HyuJ3x5RIsTxYh85hJYwNOdFLyzVG6HER9jRCnvmNTjG0O
I5wz5hQvDpwXs4BCCXHQZrTLAi3BEjq3AjrmR/XeGHulbWh3eh8LVu7MiLRgt+Ys
GnL2IaERrbkje24nCCMNPbI3fGDQEhTIYmmX8RJp+5BOJgCycKk6pFgfrjJv2C+d
78pcjlYII6M4vPnr/a08M49Bq6b5ADvIfe5G2KrUvD/+vwoAwv6d/daymHCQ2rY5
kmdVk9VUp3Q4uKoeej4ENJSAUNTV7oTu346oc7q9sJffB5OltqbrE7ichak7lL+v
EjArZHElAhKNFXRZViCMvGDs+7JztqbsfT8Xb6Z27e+WyudB2bOUGm3hKuTIl06D
bA7yUskwEhmkd1CJqO5RLEJjKitOqe6Ye0/GsmPQNDK8GvyXTyGQK5OqBuzEexF0
mlPoIhpSVH3K9SkRTTHvvcbdYlaQLi6gKq2uhbk4PnS2nfBtXqYIy9mxcgBJzLiB
/ydfLcf3GClwgvO1JHp6qAl4CO7oe8jqHpoGuznwi1aqkTyNkQWh0OXq3MS+dyqB
2yXFCFIeKCx18TE1OtuTD3ppBDjpyd0o/a6kYR3FDmdks/J33bGwLsLH3lbN6VjF
PNfNkaE1tfkpSGYsuT1DPxX8aAT4JLUfZ1Si6iO+E0Sj9LXA
-----END CERTIFICATE-----`
client_crt = `-----BEGIN CERTIFICATE-----
MIID/jCCAeYCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
ZDAeFw0xODAyMTMyMDU0MjZaFw0xOTAyMTMyMDU0MjZaMEUxCzAJBgNVBAYTAkFV
MRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz
IFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD1li7/35Q
C/T6FACSbsd0WlImu42i6w96wfngAfEgbz5Ip+IA2rJ8G5LNHTYYCpr9LlmhY6zm
soHgAkff6XwUnZaetX01UmGP4CD4D3UumkR1uKY4bCSNImm53SZgelOznpsqAWKE
zosMrDcOAJKJSN411KwVzWysfRCPyxvmLETzU9KHFCJ1oY3t1HzYIAqpHv9sMSst
dNHW3X7bWEAVKCQMKO+rWe/wAhE4iTVdlRi02oRoRWSVj41+nk6jI8KJNq70stHc
QSST0A7SUacPYKJWqJRhP1pZ6k4G3ZVE8332az7jvcN1uGGjERZoUbZxGB+mbMCC
GJwnwnNiI6/hAgMBAAEwDQYJKoZIhvcNAQELBQADggIBADNr6QMl57CdHEzNwc2M
CSZsuOLakp8YiovVDOXJ/p/lykUIIcR1rI1iNfb8oOFTZmrndGZVAh76EExdMHYG
m+4Vr2+z/73AZwvhhnLhftOKFFwkdjCfXouPlkc/zmhOORakIFGlLZFkuZRY6k2D
Q8uIt7E5uXSVl11A1LxN5X8lhK2G4lxJZuj1AqEFj9QD44Qy+MdgX38lzGCEXd8c
Y5K8zLJGbgXgYaFxqd0bImfjgjj82+Mui0OTV5PcRlczJX08ygKjcoAMVyvPHu72
3zzxvoNcqUrvbptVvg9c7FSOpK95YZOe1LiyqZCwNJQl4fPRE++XQ4zDNdyiAp76
a6BQg/M8gOpV/VBMTsNDr/yP/7eBqkfvU7jLfz7wKMDdcjeZnKom42f+/XOLEo6E
hyDuHGdQh10bZD/Ukcs69+pA3ioic1A8pQzAElH3IuDBsMJg30x8tACLKNcUY8BE
2eJgrCxWcvq88DeAT03W9AVpFZA8ZQUR3SHCquMBFogsmUDDMN+CoC0u5dBwHP+O
9rmWOXn8gp/zBCKGwemgVV5vSNzJs7z3aoqIiAABl56LBaXxjKzRmXoB/SyUW5zl
1zy4SQTE6SJYqqU6h2yRdT8n0oWN3AMy0VxbJTRq32kdYJVQK9cLKVqpxtCCtPnN
3lV+HDsj7k+AJjHiu1F4O+sp
-----END CERTIFICATE-----`
client_key = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAw9ZYu/9+UAv0+hQAkm7HdFpSJruNousPesH54AHxIG8+SKfi
ANqyfBuSzR02GAqa/S5ZoWOs5rKB4AJH3+l8FJ2WnrV9NVJhj+Ag+A91LppEdbim
OGwkjSJpud0mYHpTs56bKgFihM6LDKw3DgCSiUjeNdSsFc1srH0Qj8sb5ixE81PS
hxQidaGN7dR82CAKqR7/bDErLXTR1t1+21hAFSgkDCjvq1nv8AIROIk1XZUYtNqE
aEVklY+Nfp5OoyPCiTau9LLR3EEkk9AO0lGnD2CiVqiUYT9aWepOBt2VRPN99ms+
473DdbhhoxEWaFG2cRgfpmzAghicJ8JzYiOv4QIDAQABAoIBADKcbZhAYjt7q5cJ
nlA5svA9+2cpJ2SITRrTkKk0t0VDmpwaTw0bd+8dDSZXO0ihTQbLeLx9zwxb67ah
wEN8yuVlCK0BiFdEcBRHvx18mTMvCSxHSSXhxNx4nUw8fBOI6aLNBZqoevaJjmP7
CctjmHtESrEswkBsM36sX6BZxF8Kc4Q5Znuxqksnl6HNoxnjhmygJmYCFTToiTHa
f2HWKBiZfgfxX7WEuHer3h6nmBbBCOX1/hcipBMBBVIqFl1ZSIF/B3lR8UV4/X+a
SNMqggOqkEIuHKkSCKo1lNxEPP2p54EHrKkjepoqMzIFuYnn4qWesMznpmy+zBGB
6PCjfzUCgYEA92etvRVQjBx8dHTSiyCNbS1ELgiCkzar8PGH+ytTIaj/TTF1LfAi
UYRp5MtOKmQXxE3IRLDF8P8rEKC06aV12hVwhd2xfHjje+KZkwWZ2PIj+GbK7f1r
MvKN5eE0NhGiSvu5SiFuks/SV8Qc4StFPmiWf33XKvJuAWNkCu+bUZsCgYEAyqQL
nVNKTlgHNKDJKMHi/buZt8wtwGGXCxcv+w88PmEC0OCbH/V2niCPLvFmK1xDXpru
k7z9FTc+QeasEMtxY/Gcs3IgUzxOHxAL7cn6KBM44uDhpIcv3BFWtR053acVU6S4
IKuijWIJNJEk2qksgQTX7Mv/xq2uXvfZqajdKjMCgYEA3x+5F9s+Pm5+a4TkUSc1
hS4a3C0+ncfjv7QEwCftnGDOhu7A0IJOYRg7bGVShHaq3JaNtC19BwEJ9MALCOD5
bYqCZahvpmNcPeE6Qdb+TiLq/96sy4AOiu8nvBejv9Ode2SUUd/e2jbla9Ppe8VL
eKJYgHicchYb0dKyag54FFsCgYEAuToEB9W3aS9bvsZtuZyooSfXFcND2sMZrqCO
Uh2WAqroSQfVo/vaZiX623z62A2o4xQZmd+5MqhhdxmkFGHyDtouU3SxiYPpIMmp
Lb1etT0E1ZWbi6mqnK0YpcrGNw5gFynMyMg6eKOxKGS33EuhC3ni6Wd7MB9X8ST6
x/M73jMCgYBBge3/ugnZPE78TDL3DdefrjeYFaKhVc622eimS/MEPbkbdxh8azTM
LAoibwDU1NC8/3MfOBYMe6Qklu3kjexOJrfdo0Z7Khgd9F8A4tKwslUndSSlAfKF
2rjfqabVMZMLZ2XEbA4W5JTfaZS4YYGcrjY7+i7OsnSxoYG2sb+xlQ==
-----END RSA PRIVATE KEY-----`
)

+ 274
- 0
_dev/crypto_catalog/server.go Zobrazit soubor

@@ -0,0 +1,274 @@
package main

import (
"crypto/tls"
"crypto/x509"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
)

type ZeroRTT_t int
type Algo_t int

// Bitset
const (
ZeroRTT_None ZeroRTT_t = 0
ZeroRTT_Offer = 1 << 0
ZeroRTT_Accept = 1 << 1
)

const (
PubKeyRSA Algo_t = iota
PubKeyECDSA
KeyShareSIDH
)

type server struct {
Address string
ZeroRTT ZeroRTT_t
PubKey Algo_t
ClientAuthMethod tls.ClientAuthType
use_sidh bool
curves []tls.CurveID
}

var tlsVersionToName = map[uint16]string{
tls.VersionTLS10: "1.0",
tls.VersionTLS11: "1.1",
tls.VersionTLS12: "1.2",
tls.VersionTLS13: "1.3",
tls.VersionTLS13Draft23: "1.3 (draft 23)",
}

func NewServer() *server {
s := new(server)
s.ClientAuthMethod = tls.NoClientCert
s.ZeroRTT = ZeroRTT_None
s.Address = "0.0.0.1:443"
s.curves = []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384, tls.CurveP521}
return s
}

func (s *server) start() {
cert, err := tls.X509KeyPair([]byte(ecdsaCert), []byte(ecdsaKey))
if s.PubKey == PubKeyRSA {
cert, err = tls.X509KeyPair([]byte(rsaCert), []byte(rsaKey))
}
if err != nil {
log.Fatal(err)
}
var Max0RTTDataSize uint32
if (s.ZeroRTT & ZeroRTT_Offer) == ZeroRTT_Offer {
Max0RTTDataSize = 100 * 1024
}
var keyLogWriter io.Writer
if keyLogFile := os.Getenv("SSLKEYLOGFILE"); keyLogFile != "" {
keyLogWriter, err = os.OpenFile(keyLogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatalf("Cannot open keylog file: %v", err)
}
log.Println("Enabled keylog")
}

clientCAs := x509.NewCertPool()
clientCAs.AppendCertsFromPEM([]byte(rsaCa_client))

httpServer := &http.Server{
Addr: s.Address,
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
Max0RTTDataSize: Max0RTTDataSize,
Accept0RTTData: (s.ZeroRTT & ZeroRTT_Accept) == ZeroRTT_Accept,
KeyLogWriter: keyLogWriter,
GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
// If we send the first flight too fast, NSS sends empty early data.
time.Sleep(500 * time.Millisecond)
return nil, nil
},
MaxVersion: tls.VersionTLS13,
ClientAuth: s.ClientAuthMethod,
ClientCAs: clientCAs,
CurvePreferences: s.curves,
},
}
log.Fatal(httpServer.ListenAndServeTLS("", ""))
}

func main() {

s := NewServer()

arg_addr := flag.String("b", "0.0.0.0:443", "Address:port used for binding")
arg_palg := flag.String("palg", "rsa", "Public algorithm to use: rsa or ecdsa")
arg_zerortt := flag.String("rtt0", "n", `0-RTT, accepts following values [n: None, a: Accept, o: Offer, oa: Offer and Accept]`)
arg_confirm := flag.Bool("rtt0ack", false, "0-RTT confirm")
arg_clientauth := flag.Bool("cliauth", false, "Performs client authentication (RequireAndVerifyClientCert used)")
arg_sidhon := flag.Bool("enable_sidh", false, "Use SIDH for key exchange")
flag.Parse()

s.Address = *arg_addr

if *arg_palg == "ecdsa" {
s.PubKey = PubKeyECDSA
}

if *arg_zerortt == "a" {
s.ZeroRTT = ZeroRTT_Accept
} else if *arg_zerortt == "o" {
s.ZeroRTT = ZeroRTT_Offer
} else if *arg_zerortt == "oa" {
s.ZeroRTT = ZeroRTT_Offer | ZeroRTT_Accept
}

if *arg_clientauth {
s.ClientAuthMethod = tls.RequireAndVerifyClientCert
}

if *arg_sidhon {
s.curves = []tls.CurveID{tls.SidhP751Curve25519, tls.SidhP751Curve448}
}

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tlsConn := r.Context().Value(http.TLSConnContextKey).(*tls.Conn)

with0RTT := ""
if !tlsConn.ConnectionState().HandshakeConfirmed {
with0RTT = " [0-RTT]"
}
if *arg_confirm || r.URL.Path == "/confirm" {
if err := tlsConn.ConfirmHandshake(); err != nil {
log.Fatal(err)
}
if with0RTT != "" {
with0RTT = " [0-RTT confirmed]"
}
if !tlsConn.ConnectionState().HandshakeConfirmed {
panic("HandshakeConfirmed false after ConfirmHandshake")
}
}

resumed := ""
if r.TLS.DidResume {
resumed = " [resumed]"
}

http2 := ""
if r.ProtoMajor == 2 {
http2 = " [HTTP/2]"
}

fmt.Printf("Established: TLS ver %X CipherSuite: %X CurveID: %X\n",
r.TLS.Version,
r.TLS.CipherSuite,
tlsConn.KeyShareCurve)

fmt.Fprintf(w, "<!DOCTYPE html><p>Hello TLS %s%s%s%s _o/\n", tlsVersionToName[r.TLS.Version], resumed, with0RTT, http2)
})

http.HandleFunc("/ch", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "Client Hello packet (%d bytes):\n%s", len(r.TLS.ClientHello), hex.Dump(r.TLS.ClientHello))
})

s.start()
}

const (
rsaKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1DHcIM3SThFqy8nAkPQFX0E7ph8jqh8EATXryjKHGuVjR3Xh
OQ0BSPoJxyfdg/VEwevFrtmZAfz0WCbxvP2SVCmf7oobg4V2KPSo3nNt9vlBFUne
RtIyHRQ8YRnGSWaRHzJbX6ffltnG2aD+8qUfk161rdZgxBA9G0Ga47IkwQhT2Hqu
H3dW2Uu4W2WMyt6gX/tdyEAV57MOPcoceknr7Nb2kfiuDPR7h6wFrW3I6eoj8oX2
SkIOuVNt1Z31BAUcPJDUjqopI0o9tolM/7X13M8dEY0OJQVr7FQYDF9JeSYeEMyb
wizjBaHDm48mSghP1o5UssQBbNNC83btXCjiLQIDAQABAoIBACzvGgRAUYaCnbDl
2kdXxUN0luMIuQ6vXrO67WF17bI+XRWm2riwDlObzzJDON9Wsua1vLjYD1SickOw
i4RP1grIfbuPt1/UhT8LAC+LFgA0rBmL+OvaWw5ZWKffQ2QLujN3AG5zKB/Tog43
z4UmfldAuQxE11zta2M4M0qAUNQnQj1oiuI8RUdG0VvvLw8Htdi1ogH0CI5R669z
NjHt+JV+2gzKx6EX0s8mQL3yXGkC2xXItRbFclyCMJEhPS7QbBu+tru35N6WpzAq
BCl2Q7LQogvSA6MXuMOx6CyuExVfgmhbfeoheLE8gmXwl0Y37n/g6ZBZFAtpCjcs
UckPv0ECgYEA1orl7RwgIsZljMap6vWtMGoRIHKmT91DGpMmkh4suZe+yAk85maU
49Vd+8ZfIN41AH37yrsGOcPHgz5o5QufELpoub6DCsQ7u9F1vQp55cp+qyBWzAgz
b/xUuVnIyv3kLan3fpk7ZGCBXFBpLG0QXMFOHtda3Mlk5SmuoEYaYRkCgYEA/TLR
u4neKqyqwsqMuRJGC1iKFVmfCjZeNMtPNbTWpdqez/vvT8APnEpIumUGt8YROLGZ
8biUr5/ViOkmaP3wmQbO9m2/cE01lMTYv75w1cw2KVQe6kAHJkOx+JEx9xg53RJ/
QlFtG5MQUy2599Gxp8BMGaXLH5yo4qwvNvY6CDUCgYEArxr7AwX7rKZlZ/sV4HHY
gzVu+R7aY0DibiRATO5X7rrNuhLgI+UCDNqvNLn6FqeGdvpcsmDneeozQwmDL77G
ey7KHyBBcF4tquQQxtRwHX+i1yUz8p+W7AX1WLrRSezjeenJ2QhUE1849hGjZeE2
g546lq2Kub2enfPhVWsiSLECgYEA72T5QCPeVuLioUH5Q5Kvf1K7W+xcnr9A2xHP
Vqwgtre5qFQ/tFuXZuIlWXbjnyY6aiwhrZYjntm0f7pRgrt2nHj/fafOdVPK8Voc
xU4+SSbHntPWVw0qtVcUEjzVzRauvwMaJ43tZ0DpEnwNdO5i1oTObwF+x+jLFWZP
TdwIinECgYBzjZeCxxOMk5SlPpTsLUtgC+q3m1AavXhUVNEPP2gKMOIPTETPbhbG
LBxB2vVbJiS3J7itQy8gceT89O0vSEZnaTPXiM/Ws1QbkBJ8yW7KI7X4WuzN4Imq
/cLBRXLb8R328U27YyQFNGMjr2tX/+vx5FulJjSloWMRNuFWUngv7w==
-----END RSA PRIVATE KEY-----`
rsaCert = `-----BEGIN CERTIFICATE-----
MIIC+jCCAeKgAwIBAgIRANBDimJ/ww2tz77qcYIhuZowDQYJKoZIhvcNAQELBQAw
EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA5MjQxNzI5MTlaFw0yNjA5MjIxNzI5
MTlaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDUMdwgzdJOEWrLycCQ9AVfQTumHyOqHwQBNevKMoca5WNHdeE5DQFI
+gnHJ92D9UTB68Wu2ZkB/PRYJvG8/ZJUKZ/uihuDhXYo9Kjec232+UEVSd5G0jId
FDxhGcZJZpEfMltfp9+W2cbZoP7ypR+TXrWt1mDEED0bQZrjsiTBCFPYeq4fd1bZ
S7hbZYzK3qBf+13IQBXnsw49yhx6Sevs1vaR+K4M9HuHrAWtbcjp6iPyhfZKQg65
U23VnfUEBRw8kNSOqikjSj22iUz/tfXczx0RjQ4lBWvsVBgMX0l5Jh4QzJvCLOMF
ocObjyZKCE/WjlSyxAFs00Lzdu1cKOItAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIF
oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAygPV4enmvwSuMd1JarxOXpOK
Z4Nsk7EKlfCPgzxQUOkFdLIr5ZG1kUkQt/omzTmoIWjLAsoYzT0ZCPOrioczKsWj
MceFUIkT0w+eIl+8DzauPy34o8rjcApglF165UG3iphlpI+jdPzv5TBarUAbwsFb
ClMLEiNJQ0OMxAIaRtb2RehD4q3OWlpWf6joJ36PRBqL8T5+f2x6Tg3c64UR+QPX
98UcCQHHdEhm7y2z5Z2Wt0B48tZ+UAxDEoEwMghNyw7wUD79IRlXGYypBnXaMuLX
46aGxbsSQ7Rfg62Co3JG7vo+eJd0AoZHrtFUnfM8V70IFzMBZnSwRslHRJe56Q==
-----END CERTIFICATE-----`
rsaCa_client = `-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIJAPpBgIvtQb1EMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgwMjEzMjAxNjA3WhcNMTkwMjEzMjAxNjA3WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAr4xgdmB4DaEh8zRFmg/1ZxYhQZMUP0iQX/Y8nDWxNlcd42p3TgpY1biz
jrq58ln9Om4U/GAn2RmtBAynSBXIlR5oVa44JeMM8Ka8R/dMKyHpF0Nj2EJB9unb
TC33PfzOlnKQxATwevnnhI6tGluWmwvxXUi7WnX0di+nQg9HrIVom3KrmRr2/41y
g497ccYUuNnKE6sewGdGzw045oWZpMDA2Us+MFo1IywOurjaM9bueRhPTcIiQ8RE
h7qb+FRwfxaj9ynZA2PCM7WMSSWCiZJV0uj/pshYF2lvtJcJef4dhwnsYBpc+mgx
2q9qcUBeo3ZHbi1/PRqjwSmcW3yY5cQRbpYp6xFmgmX3oHQkVXS0UlpNVZ+morcS
HEpaK8b76fCFcL5yFsAJkPPfny1IKU+CfaVq60dM/mxbEW6J4mZT/uAiqrCilMC+
FyiATCZur8Ks7p47eZy700DllLod7gWTiuZTgHeQFVoX+jxbCZKlFn5Xspu8ALoK
Mla/q83mICRVy3+eMUsD7DNvoWYpCAYy/oMk0VWfrQ48JkCGbBW2PW/dU2nmqVhY
/11rurkr+1TUvYodnajANtXvUjW1DPOLb4dES4Qc4b7Fw8eFXrARhl5mXiL5HFKR
/VnRshiJ+QwTVkxl+KkZHEm/WS8QD+Zd8leAxh9MCoaU/XrBUBkCAwEAAaNTMFEw
HQYDVR0OBBYEFKUinuD1xRvcNd2Wti/PnBJp7On1MB8GA1UdIwQYMBaAFKUinuD1
xRvcNd2Wti/PnBJp7On1MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
ggIBAJdJrNBftqkTs2HyuJ3x5RIsTxYh85hJYwNOdFLyzVG6HER9jRCnvmNTjG0O
I5wz5hQvDpwXs4BCCXHQZrTLAi3BEjq3AjrmR/XeGHulbWh3eh8LVu7MiLRgt+Ys
GnL2IaERrbkje24nCCMNPbI3fGDQEhTIYmmX8RJp+5BOJgCycKk6pFgfrjJv2C+d
78pcjlYII6M4vPnr/a08M49Bq6b5ADvIfe5G2KrUvD/+vwoAwv6d/daymHCQ2rY5
kmdVk9VUp3Q4uKoeej4ENJSAUNTV7oTu346oc7q9sJffB5OltqbrE7ichak7lL+v
EjArZHElAhKNFXRZViCMvGDs+7JztqbsfT8Xb6Z27e+WyudB2bOUGm3hKuTIl06D
bA7yUskwEhmkd1CJqO5RLEJjKitOqe6Ye0/GsmPQNDK8GvyXTyGQK5OqBuzEexF0
mlPoIhpSVH3K9SkRTTHvvcbdYlaQLi6gKq2uhbk4PnS2nfBtXqYIy9mxcgBJzLiB
/ydfLcf3GClwgvO1JHp6qAl4CO7oe8jqHpoGuznwi1aqkTyNkQWh0OXq3MS+dyqB
2yXFCFIeKCx18TE1OtuTD3ppBDjpyd0o/a6kYR3FDmdks/J33bGwLsLH3lbN6VjF
PNfNkaE1tfkpSGYsuT1DPxX8aAT4JLUfZ1Si6iO+E0Sj9LXA
-----END CERTIFICATE-----`
ecdsaCert = `-----BEGIN CERTIFICATE-----
MIIBbTCCAROgAwIBAgIQZCsHZcs5ZkzV+zC2E6j5RzAKBggqhkjOPQQDAjASMRAw
DgYDVQQKEwdBY21lIENvMB4XDTE2MDkyNDE3NTE1OFoXDTI2MDkyMjE3NTE1OFow
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDTO
B3IyzjYfKCp2HWy+P3QHxhdBT4AUGYgwTiSEj5phumPIahFNcOSWptN0UzlZvJdN
MMjVmrFYK/FjF4abkNKjSzBJMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr
BgEFBQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDAKBggq
hkjOPQQDAgNIADBFAiEAp9W157PM1IadPBc33Cbj7vaFvp+rXs/hSuMCzP8pgV8C
IHCswo1qiC0ZjQmWsBlmz5Zbp9rOorIzBYmGRhRdNs3j
-----END CERTIFICATE-----`
ecdsaKey = `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFdhO7IW5UIwpB1e2Vunm9QyKvUHWcVwGfLjhpOajuR7oAoGCCqGSM49
AwEHoUQDQgAENM4HcjLONh8oKnYdbL4/dAfGF0FPgBQZiDBOJISPmmG6Y8hqEU1w
5Jam03RTOVm8l00wyNWasVgr8WMXhpuQ0g==
-----END EC PRIVATE KEY-----`
)

+ 41
- 14
_dev/interop_test_runner Zobrazit soubor

@@ -46,13 +46,13 @@ class RegexSelfTest(unittest.TestCase):
''' Ensures that those regexe's actually work '''

LINE_HELLO_TLS ="\nsomestuff\nHello TLS 1.3 _o/\nsomestuff"
LINE_HELLO_DRAFT_TLS="\nsomestuff\nHello TLS 1.3 (draft 22) _o/\nsomestuff"
LINE_HELLO_DRAFT_TLS="\nsomestuff\nHello TLS 1.3 (draft 23) _o/\nsomestuff"

LINE_HELLO_RESUMED ="\nsomestuff\nHello TLS 1.3 (draft 22) [resumed] _o/\nsomestuff"
LINE_HELLO_MIXED ="\nsomestuff\nHello TLS 1.3 (draft 22) _o/\nHello TLS 1.3 (draft 22) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_12 ="\nsomestuff\nHello TLS 1.2 (draft 22) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT="\nsomestuff\nHello TLS 1.3 (draft 22) [resumed] [0-RTT] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT_CONFIRMED="\nsomestuff\nHello TLS 1.3 (draft 22) [resumed] [0-RTT confirmed] _o/\nsomestuff"
LINE_HELLO_RESUMED ="\nsomestuff\nHello TLS 1.3 (draft 23) [resumed] _o/\nsomestuff"
LINE_HELLO_MIXED ="\nsomestuff\nHello TLS 1.3 (draft 23) _o/\nHello TLS 1.3 (draft 23) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_12 ="\nsomestuff\nHello TLS 1.2 (draft 23) [resumed] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT="\nsomestuff\nHello TLS 1.3 (draft 23) [resumed] [0-RTT] _o/\nsomestuff"
LINE_HELLO_TLS_13_0RTT_CONFIRMED="\nsomestuff\nHello TLS 1.3 (draft 23) [resumed] [0-RTT confirmed] _o/\nsomestuff"

def test_regexes(self):
self.assertIsNotNone(
@@ -210,14 +210,28 @@ class InteropServer_BoringSSL(
ServerNominalMixin,
ServerClientAuthMixin,
unittest.TestCase
): CLIENT_NAME = "tls-tris:boring"
):

class InteropServer_PicoTLS(
InteropServer,
ServerNominalMixin,
ServerZeroRttMixin,
unittest.TestCase
): CLIENT_NAME = "tls-tris:picotls"
CLIENT_NAME = "tls-tris:boring"

def test_qrServerAcceptsNonQR(self):
res = self.d.run_client(self.CLIENT_NAME, self.server_ip+":"+'7443')
self.assertTrue(res[0] == 0)
# Check there was TLS hello without resume
self.assertIsNotNone(
re.search(RE_PATTERN_HELLO_TLS_13_NORESUME, res[1], re.MULTILINE))
# Check there was TLS hello with resume
self.assertIsNotNone(
re.search(RE_PATTERN_HELLO_TLS_13_RESUME, res[1], re.MULTILINE))

# PicoTLS doesn't seem to implement draft-23 correctly. It will
# be enabled when draft-28 is implemented.
# class InteropServer_PicoTLS(
# InteropServer,
# ServerNominalMixin,
# ServerZeroRttMixin,
# unittest.TestCase
# ): CLIENT_NAME = "tls-tris:picotls"

class InteropServer_NSS(
InteropServer,
@@ -241,7 +255,10 @@ class InteropClient_NSS(
): SERVER_NAME = "tstclnt-localserver"

# TRIS as a client
class InteropServer_TRIS(ClientNominalMixin, InteropServer, unittest.TestCase):
class InteropServer_TRIS(
ClientNominalMixin,
InteropServer,
unittest.TestCase):

CLIENT_NAME = 'tris-testclient'

@@ -250,5 +267,15 @@ class InteropServer_TRIS(ClientNominalMixin, InteropServer, unittest.TestCase):
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=false -cliauth '+self.server_ip+":6443")
self.assertEqual(res[0], 0)

def test_qr(self):
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr SIDH-P751-X25519 '+self.server_ip+":7443")
self.assertEqual(res[0], 0)
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr SIDH-P751-X448 '+self.server_ip+":7443")
self.assertEqual(res[0], 0)

def test_qrServerAcceptsNonQR(self):
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true '+self.server_ip+":7443")
self.assertEqual(res[0], 0)

if __name__ == '__main__':
unittest.main()

+ 1
- 0
_dev/tris-localserver/Dockerfile Zobrazit soubor

@@ -8,6 +8,7 @@ EXPOSE 3443
EXPOSE 4443
EXPOSE 5443
EXPOSE 6443
EXPOSE 7443

ADD tris-localserver /
ADD runner.sh /


+ 1
- 0
_dev/tris-localserver/runner.sh Zobrazit soubor

@@ -6,5 +6,6 @@
./tris-localserver -b 0.0.0.0:4443 -palg=ecdsa -rtt0=oa 2>&1 & # fourth port: offer and accept 0-RTT
./tris-localserver -b 0.0.0.0:5443 -palg=ecdsa -rtt0=oa -rtt0ack 2>&1 & # fifth port: offer and accept 0-RTT but confirm
./tris-localserver -b 0.0.0.0:6443 -palg=rsa -cliauth 2>&1 & # sixth port: RSA with required client authentication
./tris-localserver -b 0.0.0.0:7443 -palg=ecdsa -qr & # Enables post-quantum algorithms

wait

+ 68
- 59
_dev/tris-localserver/server.go Zobrazit soubor

@@ -2,15 +2,14 @@ package main

import (
"crypto/tls"
"crypto/x509"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"crypto/x509"
)

type ZeroRTT_t int
@@ -18,21 +17,21 @@ type PubKeyAlgo_t int

// Bitset
const (
ZeroRTT_None ZeroRTT_t = 0
ZeroRTT_Offer = 1 << 0
ZeroRTT_Accept = 1 << 1
ZeroRTT_None ZeroRTT_t = 0
ZeroRTT_Offer = 1 << 0
ZeroRTT_Accept = 1 << 1
)

const (
PubKeyRSA PubKeyAlgo_t = iota
PubKeyRSA PubKeyAlgo_t = iota
PubKeyECDSA
)

type server struct {
Address string
ZeroRTT ZeroRTT_t
PubKey PubKeyAlgo_t
ClientAuthMethod tls.ClientAuthType
Address string
ZeroRTT ZeroRTT_t
PubKey PubKeyAlgo_t
TLS tls.Config
}

var tlsVersionToName = map[uint16]string{
@@ -43,14 +42,25 @@ var tlsVersionToName = map[uint16]string{
tls.VersionTLS13Draft18: "1.3 (draft 18)",
tls.VersionTLS13Draft21: "1.3 (draft 21)",
tls.VersionTLS13Draft22: "1.3 (draft 22)",
tls.VersionTLS13Draft23: "1.3 (draft 23)",
tls.VersionTLS13Draft28: "1.3 (draft 28)",
}

func NewServer() *server {
s := new(server)
s.ClientAuthMethod = tls.NoClientCert
s.ZeroRTT = ZeroRTT_None
s.Address = "0.0.0.1:443"
return s
s := new(server)
s.ZeroRTT = ZeroRTT_None
s.Address = "0.0.0.0:443"
s.TLS = tls.Config{
GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
// If we send the first flight too fast, NSS sends empty early data.
time.Sleep(500 * time.Millisecond)
return nil, nil
},
MaxVersion: tls.VersionTLS13,
ClientAuth: tls.NoClientCert,
}

return s
}

func (s *server) start() {
@@ -58,73 +68,72 @@ func (s *server) start() {
if s.PubKey == PubKeyRSA {
cert, err = tls.X509KeyPair([]byte(rsaCert), []byte(rsaKey))
}
s.TLS.Certificates = []tls.Certificate{cert}
if err != nil {
log.Fatal(err)
}
var Max0RTTDataSize uint32
if ((s.ZeroRTT&ZeroRTT_Offer) == ZeroRTT_Offer) {
Max0RTTDataSize = 100 * 1024
if (s.ZeroRTT & ZeroRTT_Offer) == ZeroRTT_Offer {
s.TLS.Max0RTTDataSize = 100 * 1024
}
var keyLogWriter io.Writer
if keyLogFile := os.Getenv("SSLKEYLOGFILE"); keyLogFile != "" {
keyLogWriter, err = os.OpenFile(keyLogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
s.TLS.KeyLogWriter, err = os.OpenFile(keyLogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatalf("Cannot open keylog file: %v", err)
}
log.Println("Enabled keylog")
}

clientCAs := x509.NewCertPool()
clientCAs.AppendCertsFromPEM([]byte(rsaCa_client))
s.TLS.ClientCAs = x509.NewCertPool()
s.TLS.ClientCAs.AppendCertsFromPEM([]byte(rsaCa_client))
s.TLS.Accept0RTTData = ((s.ZeroRTT & ZeroRTT_Accept) == ZeroRTT_Accept)

httpServer := &http.Server{
Addr: s.Address,
TLSConfig: &tls.Config{
Certificates: []tls.Certificate{cert},
Max0RTTDataSize: Max0RTTDataSize,
Accept0RTTData: (s.ZeroRTT&ZeroRTT_Accept) == ZeroRTT_Accept,
KeyLogWriter: keyLogWriter,
GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) {
// If we send the first flight too fast, NSS sends empty early data.
time.Sleep(500 * time.Millisecond)
return nil, nil
},
MaxVersion: tls.VersionTLS13,
ClientAuth: s.ClientAuthMethod,
ClientCAs: clientCAs,
},
Addr: s.Address,
TLSConfig: &s.TLS,
}
log.Fatal(httpServer.ListenAndServeTLS("", ""))
}

func enableQR(s *server) {
var defaultCurvePreferences = []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384, tls.CurveP521}
var sidhCurves = []tls.CurveID{tls.SidhP751Curve25519, tls.SidhP751Curve448}
s.TLS.CurvePreferences = append(defaultCurvePreferences, sidhCurves...)
}

func main() {

s := NewServer()
s := NewServer()

arg_addr := flag.String("b" , "0.0.0.0:443", "Address:port used for binding")
arg_palg := flag.String("palg", "rsa", "Public algorithm to use: rsa or ecdsa")
arg_zerortt := flag.String("rtt0", "n", `0-RTT, accepts following values [n: None, a: Accept, o: Offer, oa: Offer and Accept]`)
arg_confirm := flag.Bool("rtt0ack", false, "0-RTT confirm")
arg_clientauth := flag.Bool("cliauth", false, "Performs client authentication (RequireAndVerifyClientCert used)")
flag.Parse()
arg_addr := flag.String("b", "0.0.0.0:443", "Address:port used for binding")
arg_palg := flag.String("palg", "rsa", "Public algorithm to use: rsa or ecdsa")
arg_zerortt := flag.String("rtt0", "n", `0-RTT, accepts following values [n: None, a: Accept, o: Offer, oa: Offer and Accept]`)
arg_confirm := flag.Bool("rtt0ack", false, "0-RTT confirm")
arg_clientauth := flag.Bool("cliauth", false, "Performs client authentication (RequireAndVerifyClientCert used)")
arg_qr := flag.Bool("qr", false, "Enable quantum-resistant algorithms")
flag.Parse()

s.Address=*arg_addr
s.Address = *arg_addr

if *arg_palg == "ecdsa" {
s.PubKey = PubKeyECDSA
}
if *arg_palg == "ecdsa" {
s.PubKey = PubKeyECDSA
}

if *arg_zerortt == "a" {
s.ZeroRTT = ZeroRTT_Accept
} else if *arg_zerortt == "o" {
s.ZeroRTT = ZeroRTT_Offer
} else if *arg_zerortt == "oa" {
s.ZeroRTT = ZeroRTT_Offer | ZeroRTT_Accept
}
if *arg_zerortt == "a" {
s.ZeroRTT = ZeroRTT_Accept
} else if *arg_zerortt == "o" {
s.ZeroRTT = ZeroRTT_Offer
} else if *arg_zerortt == "oa" {
s.ZeroRTT = ZeroRTT_Offer | ZeroRTT_Accept
}

if *arg_clientauth {
s.ClientAuthMethod = tls.RequireAndVerifyClientCert
}
if *arg_clientauth {
s.TLS.ClientAuth = tls.RequireAndVerifyClientCert
}

if *arg_qr {
enableQR(s)
}

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
tlsConn := r.Context().Value(http.TLSConnContextKey).(*tls.Conn)
@@ -212,7 +221,7 @@ ClMLEiNJQ0OMxAIaRtb2RehD4q3OWlpWf6joJ36PRBqL8T5+f2x6Tg3c64UR+QPX
98UcCQHHdEhm7y2z5Z2Wt0B48tZ+UAxDEoEwMghNyw7wUD79IRlXGYypBnXaMuLX
46aGxbsSQ7Rfg62Co3JG7vo+eJd0AoZHrtFUnfM8V70IFzMBZnSwRslHRJe56Q==
-----END CERTIFICATE-----`
rsaCa_client = `-----BEGIN CERTIFICATE-----
rsaCa_client = `-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIJAPpBgIvtQb1EMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgwMjEzMjAxNjA3WhcNMTkwMjEzMjAxNjA3WjBF


+ 95
- 39
_dev/tris-testclient/client.go Zobrazit soubor

@@ -17,6 +17,8 @@ var tlsVersionToName = map[uint16]string{
tls.VersionTLS12: "1.2",
tls.VersionTLS13: "1.3",
tls.VersionTLS13Draft18: "1.3 (draft 18)",
tls.VersionTLS13Draft23: "1.3 (draft 23)",
tls.VersionTLS13Draft28: "1.3 (draft 28)",
}

var cipherSuiteIdToName = map[uint16]string{
@@ -27,28 +29,42 @@ var cipherSuiteIdToName = map[uint16]string{
tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256",
}

var failed uint

const (
qr_algos = "[SIDH-P751-X448, SIDH-P503-X25519, SIDH-P751-X25519]"
)

type Client struct {
KeyLogWriter io.Writer
failed uint
client_cert tls.Certificate
client_certpool *x509.CertPool
TLS tls.Config
addr string
}

func (c *Client) run(addr string, version, cipherSuite uint16) {
fmt.Printf("TLS %s with %s\n", tlsVersionToName[version], cipherSuiteIdToName[cipherSuite])
tls_config := &tls.Config{
InsecureSkipVerify: true,
MinVersion: version,
MaxVersion: version,
CipherSuites: []uint16{cipherSuite},
KeyLogWriter: c.KeyLogWriter,
Certificates: []tls.Certificate{c.client_cert},
RootCAs: c.client_certpool,
}
con, err := tls.Dial("tcp", addr, tls_config)
func NewClient() *Client {
var c Client
c.TLS.InsecureSkipVerify = true
return &c
}

func (c *Client) clone() *Client {
var clone Client
clone.TLS = *c.TLS.Clone()
clone.addr = c.addr
return &clone
}

func (c *Client) setMinMaxTLS(ver uint16) {
c.TLS.MinVersion = ver
c.TLS.MaxVersion = ver
}

func (c *Client) run() {
fmt.Printf("TLS %s with %s\n", tlsVersionToName[c.TLS.MinVersion], cipherSuiteIdToName[c.TLS.CipherSuites[0]])

con, err := tls.Dial("tcp", c.addr, &c.TLS)
if err != nil {
fmt.Printf("handshake failed: %v\n\n", err)
c.failed++
failed++
return
}
defer con.Close()
@@ -56,7 +72,7 @@ func (c *Client) run(addr string, version, cipherSuite uint16) {
_, err = con.Write([]byte("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"))
if err != nil {
fmt.Printf("Write failed: %v\n\n", err)
c.failed++
failed++
return
}

@@ -66,7 +82,7 @@ func (c *Client) run(addr string, version, cipherSuite uint16) {
// is received right after reading data (observed with NSS selfserv).
if !(n > 0 && err == io.EOF) && err != nil {
fmt.Printf("Read failed: %v\n\n", err)
c.failed++
failed++
return
}
fmt.Printf("Read %d bytes\n", n)
@@ -74,25 +90,47 @@ func (c *Client) run(addr string, version, cipherSuite uint16) {
fmt.Println("OK\n")
}

func result() {
if failed > 0 {
log.Fatalf("Failed handshakes: %d\n", failed)
} else {
fmt.Println("All handshakes passed")
}
}

func setQrAlgo(qr string, client *Client) {
switch qr {
case "SIDH-P751-X448":
client.TLS.CurvePreferences = []tls.CurveID{tls.SidhP751Curve448}
case "SIDH-P503-X25519":
//client.TLS.CurvePreferences = []tls.CurveID{tls.SidhP503Curve25519}
panic("UNSUPPORTED")
case "SIDH-P751-X25519":
client.TLS.CurvePreferences = []tls.CurveID{tls.SidhP751Curve25519}
}
}

func main() {
var keylog_file string
var keylog_file, qr string
var enable_rsa, enable_ecdsa, client_auth bool

flag.StringVar(&keylog_file, "keylogfile", "", "Secrets will be logged here")
flag.BoolVar(&enable_rsa, "rsa", true, "Whether to enable RSA cipher suites")
flag.BoolVar(&enable_ecdsa, "ecdsa", true, "Whether to enable ECDSA cipher suites")
flag.BoolVar(&client_auth, "cliauth", false, "Whether to enable client authentication")
flag.StringVar(&qr, "qr", "", "Specifies qr algorithm from following list:\n"+qr_algos)
flag.Parse()
if flag.NArg() != 1 {
flag.Usage()
os.Exit(1)
}
addr := flag.Arg(0)
if !strings.Contains(addr, ":") {
addr += ":443"

client := NewClient()
client.addr = flag.Arg(0)
if !strings.Contains(client.addr, ":") {
client.addr += ":443"
}

client := Client{}
if keylog_file == "" {
keylog_file = os.Getenv("SSLKEYLOGFILE")
}
@@ -101,45 +139,64 @@ func main() {
if err != nil {
log.Fatalf("Cannot open keylog file: %v", err)
}
client.KeyLogWriter = keylog_writer
client.TLS.KeyLogWriter = keylog_writer
log.Println("Enabled keylog")
}

if client_auth {
var err error
client.client_cert, err = tls.X509KeyPair([]byte(client_crt), []byte(client_key))
client_cert, err := tls.X509KeyPair([]byte(client_crt), []byte(client_key))
if err != nil {
panic("Can't load client certificate")
}

client.client_certpool = x509.NewCertPool()
if !client.client_certpool.AppendCertsFromPEM([]byte(client_ca)) {
client.TLS.Certificates = []tls.Certificate{client_cert}
client.TLS.RootCAs = x509.NewCertPool()
if !client.TLS.RootCAs.AppendCertsFromPEM([]byte(client_ca)) {
panic("Can't load client CA cert")
}
}

if len(qr) > 0 {
setQrAlgo(qr, client)
c := client.clone()
c.TLS.CipherSuites = []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
c.setMinMaxTLS(tls.VersionTLS13)
c.run()
return
}

if enable_rsa {
// Sanity check: TLS 1.2 with the mandatory cipher suite from RFC 5246
client.run(addr, tls.VersionTLS12, tls.TLS_RSA_WITH_AES_128_CBC_SHA)
c := client.clone()
c.TLS.CipherSuites = []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA}
c.setMinMaxTLS(tls.VersionTLS12)
c.run()
}
if enable_ecdsa {
// Sane cipher suite for TLS 1.2 with an ECDSA cert (as used by boringssl)
client.run(addr, tls.VersionTLS12, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
c := client.clone()
c.TLS.CipherSuites = []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
c.setMinMaxTLS(tls.VersionTLS12)
c.run()
}

client.setMinMaxTLS(tls.VersionTLS13)
client.TLS.CipherSuites = []uint16{tls.TLS_CHACHA20_POLY1305_SHA256}
client.run()

client.run(addr, tls.VersionTLS13, tls.TLS_CHACHA20_POLY1305_SHA256)
client.run(addr, tls.VersionTLS13, tls.TLS_AES_128_GCM_SHA256)
client.run(addr, tls.VersionTLS13, tls.TLS_AES_256_GCM_SHA384)
client.setMinMaxTLS(tls.VersionTLS13)
client.TLS.CipherSuites = []uint16{tls.TLS_AES_128_GCM_SHA256}
client.run()

client.setMinMaxTLS(tls.VersionTLS13)
client.TLS.CipherSuites = []uint16{tls.TLS_AES_256_GCM_SHA384}
client.run()

// TODO test other kex methods besides X25519, like MTI secp256r1
// TODO limit supported groups?

if client.failed > 0 {
log.Fatalf("Failed handshakes: %d\n", client.failed)
} else {
fmt.Println("All handshakes passed")
}
result()
}

const (
@@ -226,4 +283,3 @@ LAoibwDU1NC8/3MfOBYMe6Qklu3kjexOJrfdo0Z7Khgd9F8A4tKwslUndSSlAfKF
2rjfqabVMZMLZ2XEbA4W5JTfaZS4YYGcrjY7+i7OsnSxoYG2sb+xlQ==
-----END RSA PRIVATE KEY-----`
)


+ 7
- 1
_dev/tstclnt/Dockerfile Zobrazit soubor

@@ -21,7 +21,13 @@ ENV USE_64=1 NSS_ENABLE_TLS_1_3=1
# ARG REVISION=e61c0f657100

# Draft 22
ARG REVISION=88c3f3fa581b
#ARG REVISION=88c3f3fa581b

# Draft 23
# ARG REVISION=16c622c9e1cc

# Latest
ARG REVISION=09ab3310e710

RUN cd nss && hg pull
RUN cd nss && hg checkout -C $REVISION


+ 20
- 0
_dev/utils/fmtcheck.sh Zobrazit soubor

@@ -0,0 +1,20 @@
#!/bin/sh
# Copyright 2012 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.

gofiles=$(find . -iname "*.go" ! -path "*/_dev/*")
#[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

# Some files are not gofmt'd. Print message and fail.

echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done

exit 1


+ 27
- 0
_dev/utils/pre-commit Zobrazit soubor

@@ -0,0 +1,27 @@
#!/bin/sh
# Copyright 2012 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.

# git gofmt pre-commit hook
#
# To use, store as .git/hooks/pre-commit inside your repository and make sure
# it has execute permissions.
#
# This script does not handle file names that contain spaces.

gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')
[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

# Some files are not gofmt'd. Print message and fail.

echo >&2 "Go files must be formatted with gofmt. Please run:"
for fn in $unformatted; do
echo >&2 " gofmt -w $PWD/$fn"
done

exit 1


+ 12
- 1
cipher_suites.go Zobrazit soubor

@@ -110,6 +110,9 @@ var cipherSuites = []*cipherSuite{
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},

// Experimental TLS 1.3 cipher suites
{TLS_ECDHE_SIDH_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, nil, suiteDefaultOff | suiteTLS13, nil, nil, aeadAESGCM13},
}

func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -174,7 +177,10 @@ type fixedNonceAEAD struct {
aead cipher.AEAD
}

func (f *fixedNonceAEAD) NonceSize() int { return 8 }
func (f *fixedNonceAEAD) NonceSize() int { return 8 }

// Overhead returns the maximum difference between the lengths of a
// plaintext and its ciphertext.
func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
func (f *fixedNonceAEAD) explicitNonceLen() int { return 8 }

@@ -418,6 +424,11 @@ const (
TLS_AES_256_GCM_SHA384 uint16 = 0x1302
TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303

// SIDH (OZAPTF: I'm not sure about IDs - it's unasigned, but not reserved/private)
TLS_ECDHE_SIDH_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0x1304
// OZAPTF, AES 256?
TLS_ECDHE_SIDH_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0x1305

// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
// that the client is doing version fallback. See
// https://tools.ietf.org/html/rfc7507.


+ 29
- 19
common.go Zobrazit soubor

@@ -30,6 +30,8 @@ const (
VersionTLS13Draft18 = 0x7f00 | 18
VersionTLS13Draft21 = 0x7f00 | 21
VersionTLS13Draft22 = 0x7f00 | 22
VersionTLS13Draft23 = 0x7f00 | 23
VersionTLS13Draft28 = 0x7f00 | 28
)

const (
@@ -40,7 +42,7 @@ const (
maxWarnAlertCount = 5 // maximum number of consecutive warning alerts

minVersion = VersionTLS12
maxVersion = VersionTLS13Draft22
maxVersion = VersionTLS13Draft28
)

// TLS record types.
@@ -79,22 +81,23 @@ const (

// TLS extension numbers
const (
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
extensionSessionTicket uint16 = 35
extensionKeyShare uint16 = 40
extensionPreSharedKey uint16 = 41
extensionEarlyData uint16 = 42
extensionSupportedVersions uint16 = 43
extensionPSKKeyExchangeModes uint16 = 45
extensionCAs uint16 = 47
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
extensionServerName uint16 = 0
extensionStatusRequest uint16 = 5
extensionSupportedCurves uint16 = 10 // Supported Groups in 1.3 nomenclature
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
extensionALPN uint16 = 16
extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
extensionSessionTicket uint16 = 35
extensionPreSharedKey uint16 = 41
extensionEarlyData uint16 = 42
extensionSupportedVersions uint16 = 43
extensionPSKKeyExchangeModes uint16 = 45
extensionCAs uint16 = 47
extensionSignatureAlgorithmsCert uint16 = 50
extensionKeyShare uint16 = 51
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
)

// TLS signaling cipher suite values
@@ -120,6 +123,12 @@ const (
CurveP384 CurveID = 24
CurveP521 CurveID = 25
X25519 CurveID = 29

SidhP503Curve25519 CurveID = 0x0105
// X448 + P751
SidhP751Curve448 CurveID = 0x0106
// X25519 + P751
SidhP751Curve25519 CurveID = 0x0107
)

// TLS 1.3 Key Share
@@ -234,7 +243,8 @@ type ConnectionState struct {
// Unique0RTTToken is only present if HandshakeConfirmed is false.
Unique0RTTToken []byte

ClientHello []byte // ClientHello packet
ClientHello []byte // ClientHello packet
KeyShareCurve CurveID
}

// ClientAuthType declares the policy the server will follow for
@@ -858,7 +868,7 @@ var configSuppVersArray = [...]uint16{VersionTLS13, VersionTLS12, VersionTLS11,
// with TLS 1.3 draft versions included.
//
// TODO: remove once TLS 1.3 is finalised.
var tls13DraftSuppVersArray = [...]uint16{VersionTLS13Draft22, VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
var tls13DraftSuppVersArray = [...]uint16{VersionTLS13Draft28, VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}

// getSupportedVersions returns the protocol versions that are supported by the
// current configuration.


+ 28
- 14
conn.go Zobrazit soubor

@@ -11,6 +11,7 @@ import (
"crypto/cipher"
"crypto/subtle"
"crypto/x509"
"encoding/binary"
"errors"
"fmt"
"io"
@@ -125,6 +126,9 @@ type Conn struct {
binder []byte

tmp [16]byte

// OZAPTF: Stores curve ID established during TLS 1.3 handshake
KeyShareCurve CurveID
}

type handshakeStatus int
@@ -355,6 +359,15 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
hc.additionalData[11] = byte(n >> 8)
hc.additionalData[12] = byte(n)
additionalData = hc.additionalData[:]
} else {
if len(payload) > int((1<<14)+256) {
return false, 0, alertRecordOverflow
}
// Check AD header, see 5.2 of RFC8446
additionalData = make([]byte, 5)
additionalData[0] = byte(recordTypeApplicationData)
binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12)
binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload)))
}
var err error
payload, err = c.Open(payload[:0], nonce, payload, additionalData)
@@ -458,12 +471,6 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
c.XORKeyStream(payload, payload)
case aead:
payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
overhead := c.Overhead()
if hc.version >= VersionTLS13 {
overhead++
}
b.resize(len(b.data) + overhead)

nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
if len(nonce) == 0 {
nonce = hc.seq[:]
@@ -475,18 +482,25 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
if hc.version < VersionTLS13 {
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
hc.additionalData[11] = byte(payloadLen >> 8)
hc.additionalData[12] = byte(payloadLen)
binary.BigEndian.PutUint16(hc.additionalData[11:], uint16(payloadLen))
additionalData = hc.additionalData[:]
}
b.resize(len(b.data) + c.Overhead())
} else {
// 1 byte of content type is appended to payload and encrypted
payload = append(payload, b.data[0])

if hc.version >= VersionTLS13 {
// opaque type
payload = payload[:len(payload)+1]
payload[len(payload)-1] = b.data[0]
// opaque_type
b.data[0] = byte(recordTypeApplicationData)
}

// Add AD header, see 5.2 of RFC8446
additionalData = make([]byte, 5)
additionalData[0] = b.data[0]
binary.BigEndian.PutUint16(additionalData[1:], VersionTLS12)
binary.BigEndian.PutUint16(additionalData[3:], uint16(len(payload)+c.Overhead()))

// make room for TLSCiphertext.encrypted_record
b.resize(len(payload) + recordHeaderLen + c.Overhead())
}
c.Seal(payload[:0], nonce, payload, additionalData)
case cbcMode:
blockSize := c.BlockSize()


+ 4
- 4
example_test.go Zobrazit soubor

@@ -155,8 +155,8 @@ func ExampleConfig_keyLogWriter_TLS13() {
// preferences.

// Output:
// CLIENT_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 ab02b68658d18ef1a4056b3094fe511b43084d40e9a6518753a7f832da724292
// SERVER_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 d2e96648d170e2524bee07b651f4cca932a52247493ca33cc0714260a7424b2d
// SERVER_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 371fab23269e3cd73496e0e78f3dbc487f7cd5a563cc9f8c1a71be242268c375
// CLIENT_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 ca30484e48ec9a6f3b05b41c7492dbed8dea8e92d2abece2824a96052ac8ed8d
// CLIENT_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 16ca97d21087a14d406b2601b4713dd82b156cc01d54665baaa4bdb62b72b9a4
// SERVER_HANDSHAKE_TRAFFIC_SECRET 0000000000000000000000000000000000000000000000000000000000000000 102c68d960da4f5e2b76a99636ac07bb5774e43b8ce8c14aa4dfd9bf54d11754
// SERVER_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 f3208d533bb885f32f52142acb484eed104739970c2f426e72a1ee31f6d28650
// CLIENT_TRAFFIC_SECRET_0 0000000000000000000000000000000000000000000000000000000000000000 70de6b1936df7db171c02f9cfdb04dfa9405a891c959beb15b86f26b2057ba23
}

+ 2
- 1
handshake_client.go Zobrazit soubor

@@ -106,6 +106,7 @@ NextCipherSuite:
hello.vers = VersionTLS12
hello.supportedVersions = config.getSupportedVersions()
hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms13
hello.supportedSignatureAlgorithmsCert = supportedSigAlgorithmsCert(supportedSignatureAlgorithms13)
}

return hello, nil
@@ -191,7 +192,7 @@ func (c *Conn) clientHandshake() error {
// Create one keyshare for the first default curve. If it is not
// appropriate, the server should raise a HRR.
defaultGroup := c.config.curvePreferences()[0]
hs.privateKey, clientKS, err = c.config.generateKeyShare(defaultGroup)
hs.privateKey, clientKS, err = c.config.generateKeyShare(defaultGroup, kRole_Client)
if err != nil {
c.sendAlert(alertInternalError)
return err


+ 117
- 75
handshake_messages.go Zobrazit soubor

@@ -6,81 +6,97 @@ package tls

import (
"bytes"
"encoding/binary"
"strings"
)

// signAlgosCertList helper function returns either list of signature algorithms in case
// signature_algorithms_cert extension should be marshalled or nil in the other case.
// signAlgos is a list of algorithms from signature_algorithms extension. signAlgosCert is a list
// of algorithms from signature_algorithms_cert extension.
func signAlgosCertList(signAlgos, signAlgosCert []SignatureScheme) []SignatureScheme {
if eqSignatureAlgorithms(signAlgos, signAlgosCert) {
// ensure that only supported_algorithms extension is send if supported_algorithms_cert
// has identical content
return nil
}
return signAlgosCert
}

type clientHelloMsg struct {
raw []byte
rawTruncated []byte // for PSK binding
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
supportedSignatureAlgorithms []SignatureScheme
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
keyShares []keyShare
supportedVersions []uint16
psks []psk
pskKeyExchangeModes []uint8
earlyData bool
raw []byte
rawTruncated []byte // for PSK binding
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
supportedSignatureAlgorithms []SignatureScheme
supportedSignatureAlgorithmsCert []SignatureScheme
secureRenegotiation []byte
secureRenegotiationSupported bool
alpnProtocols []string
keyShares []keyShare
supportedVersions []uint16
psks []psk
pskKeyExchangeModes []uint8
earlyData bool
}

// Helpers

// Marshalling of signature_algorithms extension see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// for more details. Extension is serialized in data buffer
// Function used for signature_algorithms and signature_algorithrms_cert extensions only
// (for more details, see TLS 1.3 draft 28, 4.2.3)
// Function advances data slice and returns it, so that it can be used for further processing
func marshalExtensionSignatureAlgorithms(data []byte, sigSchemes []SignatureScheme) []byte {
data[0] = byte(extensionSignatureAlgorithms >> 8)
data[1] = byte(extensionSignatureAlgorithms)
l := 2 + 2*len(sigSchemes)
data[2] = byte(l >> 8)
data[3] = byte(l)
data = data[4:]
func marshalExtensionSignatureAlgorithms(extension uint16, data []byte, schemes []SignatureScheme) []byte {
algNum := uint16(len(schemes))
if algNum == 0 {
return data
}

l -= 2
data[0] = byte(l >> 8)
data[1] = byte(l)
binary.BigEndian.PutUint16(data, extension)
data = data[2:]
binary.BigEndian.PutUint16(data, (2*algNum)+2) // +1 for length
data = data[2:]
binary.BigEndian.PutUint16(data, (2 * algNum))
data = data[2:]
for _, sigAlgo := range sigSchemes {
data[0] = byte(sigAlgo >> 8)
data[1] = byte(sigAlgo)
for _, algo := range schemes {
binary.BigEndian.PutUint16(data, uint16(algo))
data = data[2:]
}
return data
}

// Unmrshalling of signature_algorithms extension see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// for more details.
// Function used for unmarshalling signature_algorithms or signature_algorithms_cert extensions only
// (for more details, see TLS 1.3 draft 28, 4.2.3)
// In case of error function returns alertDecoderError otherwise filled SignatureScheme slice and alertSuccess
func unmarshalExtensionSignatureAlgorithms(data []byte, length int) ([]SignatureScheme, alert) {

if length < 2 || length&1 != 0 {
return nil, alertDecodeError
}

l := int(data[0])<<8 | int(data[1])
if l != length-2 {
algLen := binary.BigEndian.Uint16(data)
idx := 2

if int(algLen) != length-2 {
return nil, alertDecodeError
}
n := l / 2
d := data[2:]
sigSchemes := make([]SignatureScheme, n)
for i := range sigSchemes {
sigSchemes[i] = SignatureScheme(d[0])<<8 | SignatureScheme(d[1])
d = d[2:]

schemes := make([]SignatureScheme, algLen/2)
for i := range schemes {
schemes[i] = SignatureScheme(binary.BigEndian.Uint16(data[idx:]))
idx += 2
}
return sigSchemes, alertSuccess
return schemes, alertSuccess
}

func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -104,6 +120,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert) &&
m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
@@ -120,6 +137,8 @@ func (m *clientHelloMsg) marshal() []byte {
length := 2 + 32 + 1 + len(m.sessionId) + 2 + len(m.cipherSuites)*2 + 1 + len(m.compressionMethods)
numExtensions := 0
extensionsLength := 0

// Indicates wether to send signature_algorithms_cert extension
if m.nextProtoNeg {
numExtensions++
}
@@ -147,6 +166,10 @@ func (m *clientHelloMsg) marshal() []byte {
extensionsLength += 2 + 2*len(m.supportedSignatureAlgorithms)
numExtensions++
}
if m.getSignatureAlgorithmsCert() != nil {
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
numExtensions++
}
if m.secureRenegotiationSupported {
extensionsLength += 1 + len(m.secureRenegotiation)
numExtensions++
@@ -305,26 +328,15 @@ func (m *clientHelloMsg) marshal() []byte {
copy(z, m.sessionTicket)
z = z[len(m.sessionTicket):]
}
if len(m.supportedSignatureAlgorithms) > 0 {
// https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3
z[0] = byte(extensionSignatureAlgorithms >> 8)
z[1] = byte(extensionSignatureAlgorithms)
l := 2 + 2*len(m.supportedSignatureAlgorithms)
z[2] = byte(l >> 8)
z[3] = byte(l)
z = z[4:]

l -= 2
z[0] = byte(l >> 8)
z[1] = byte(l)
z = z[2:]
for _, sigAlgo := range m.supportedSignatureAlgorithms {
z[0] = byte(sigAlgo >> 8)
z[1] = byte(sigAlgo)
z = z[2:]
}
if len(m.supportedSignatureAlgorithms) > 0 {
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)
}
if m.getSignatureAlgorithmsCert() != nil {
// Ensure only one list of algorithms is sent if supported_algorithms and supported_algorithms_cert are the same
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
}

if m.secureRenegotiationSupported {
z[0] = byte(extensionRenegotiationInfo >> 8)
z[1] = byte(extensionRenegotiationInfo & 0xff)
@@ -743,6 +755,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert {
return alertSuccess
}

func (m *clientHelloMsg) getSignatureAlgorithmsCert() []SignatureScheme {
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
}

type serverHelloMsg struct {
raw []byte
vers uint16
@@ -1069,7 +1085,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) alert {
if m.vers != VersionTLS12 {
return alertDecodeError
}
m.vers = uint16(svData[0])<<8 | uint16(svData[1])
rcvVer := binary.BigEndian.Uint16(svData[0:])
if rcvVer < VersionTLS13 {
return alertIllegalParameter
}
m.vers = rcvVer
}

for len(data) != 0 {
@@ -2074,15 +2094,17 @@ func (m *certificateRequestMsg) unmarshal(data []byte) alert {
if len(data) != 0 {
return alertDecodeError
}

return alertSuccess
}

type certificateRequestMsg13 struct {
raw []byte

requestContext []byte
supportedSignatureAlgorithms []SignatureScheme
certificateAuthorities [][]byte
requestContext []byte
supportedSignatureAlgorithms []SignatureScheme
supportedSignatureAlgorithmsCert []SignatureScheme
certificateAuthorities [][]byte
}

func (m *certificateRequestMsg13) equal(i interface{}) bool {
@@ -2091,7 +2113,8 @@ func (m *certificateRequestMsg13) equal(i interface{}) bool {
bytes.Equal(m.raw, m1.raw) &&
bytes.Equal(m.requestContext, m1.requestContext) &&
eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms)
eqSignatureAlgorithms(m.supportedSignatureAlgorithms, m1.supportedSignatureAlgorithms) &&
eqSignatureAlgorithms(m.supportedSignatureAlgorithmsCert, m1.supportedSignatureAlgorithmsCert)
}

func (m *certificateRequestMsg13) marshal() (x []byte) {
@@ -2104,6 +2127,11 @@ func (m *certificateRequestMsg13) marshal() (x []byte) {
numExtensions := 1
extensionsLength := 2 + 2*len(m.supportedSignatureAlgorithms)

if m.getSignatureAlgorithmsCert() != nil {
numExtensions += 1
extensionsLength += 2 + 2*len(m.getSignatureAlgorithmsCert())
}

casLength := 0
if len(m.certificateAuthorities) > 0 {
for _, ca := range m.certificateAuthorities {
@@ -2131,7 +2159,11 @@ func (m *certificateRequestMsg13) marshal() (x []byte) {
z = z[2:]

// TODO: this function should be reused by CH
z = marshalExtensionSignatureAlgorithms(z, m.supportedSignatureAlgorithms)
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithms, z, m.supportedSignatureAlgorithms)

if m.getSignatureAlgorithmsCert() != nil {
z = marshalExtensionSignatureAlgorithms(extensionSignatureAlgorithmsCert, z, m.getSignatureAlgorithmsCert())
}
// certificate_authorities
if casLength > 0 {
z[0] = byte(extensionCAs >> 8)
@@ -2204,6 +2236,12 @@ func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
if err != alertSuccess {
return err
}
case extensionSignatureAlgorithmsCert:
var err alert
m.supportedSignatureAlgorithmsCert, err = unmarshalExtensionSignatureAlgorithms(data, length)
if err != alertSuccess {
return err
}
case extensionCAs:
// TODO DRY: share code with CH
if length < 2 {
@@ -2240,6 +2278,10 @@ func (m *certificateRequestMsg13) unmarshal(data []byte) alert {
return alertSuccess
}

func (m *certificateRequestMsg13) getSignatureAlgorithmsCert() []SignatureScheme {
return signAlgosCertList(m.supportedSignatureAlgorithms, m.supportedSignatureAlgorithmsCert)
}

type certificateVerifyMsg struct {
raw []byte
hasSignatureAndHash bool


+ 4
- 6
handshake_server_test.go Zobrazit soubor

@@ -197,9 +197,9 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {

func TestRenegotiationExtension(t *testing.T) {
clientHello := &clientHelloMsg{
vers: VersionTLS12,
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
vers: VersionTLS12,
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
secureRenegotiationSupported: true,
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
}
@@ -394,8 +394,6 @@ func TestSCTHandshake(t *testing.T) {
PrivateKey: testRSAPrivateKey,
SignedCertificateTimestamps: expected,
}},
// See GH#76
MaxVersion: VersionTLS12,
}
clientConfig := &Config{
InsecureSkipVerify: true,
@@ -1004,7 +1002,7 @@ func TestFallbackSCSV(t *testing.T) {
name: "FallbackSCSV",
config: &serverConfig,
// OpenSSL 1.0.1j is needed for the -fallback_scsv option.
command: []string{"openssl", "s_client", "-fallback_scsv"},
command: []string{"openssl", "s_client", "-fallback_scsv"},
expectHandshakeErrorIncluding: "inappropriate protocol fallback",
}
runServerTestTLS11(t, test)


Načítá se…
Zrušit
Uložit