コミットを比較

...

26 コミット

作成者 SHA1 メッセージ 日付
  Kris Kwiatkowski 69c276c627 test: check if tris and bssl can still connect without qr 6年前
  Kris Kwiatkowski 2411297a28 adds SIDH to interoperability tests (tris-tris) 6年前
  Henry D. Case c02cc0e83a Adds SIDH751-X448 support 6年前
  Henry D. Case 44d58d9e5c Change IDs for hybrid key exchange 6年前
  Henry D. Case aedcb7cf3c Sets curve ID established during TLS 1.3 handshake 6年前
  Henry D. Case 4386d89c02 Introduces crypto_catalog 6年前
  Henry D. Case 736ba21160 use NOBS_REPO from env if defined 6年前
  Henry D. Case 35ba04f0a1 Works 6年前
  Henry D. Case 0f8234a803 temporary: adds swap_tls target 6年前
  Henry D. Case 772c98f5ed vendors nobs-crypto in go-crypto 6年前
  Henry D. Case f3d880878e SIDH: Init 6年前
  Kris Kwiatkowski 49bb3bdab8 refactoring of the tris test client 6年前
  Kris Kwiatkowski d7f149b717 refactoring of the tris test server 6年前
  Henry D. Case 031d89f0fb refactors record encryption code 6年前
  Henry Case 8d3ff2b07d server must NOT send version prior to TLS1.3 in supported_versions (#119) 6年前
  Henry D. Case 905048a9b0 Use binary interface to encode in big-endian 6年前
  Henry Case 0caaafafe3 tls13: adds additional data to AEAD (#114) 6年前
  Henry D. Case 3ff71dcdc5 tests: enable client authentication in bogo 6年前
  Henry D. Case 6e4abe2d07 TLSv1.3 draft-23: align tests 6年前
  Henry D. Case 03138ec18e TLSv1.3 -draft23: Implementation of signature_algorithms_cert 6年前
  Henry D. Case 5bdf1af124 TLS1.3 -draft23: Renumber key_share 6年前
  Evan Klitzke 67bc308e04 Update client SCT list during TLS 1.3 handshake, fixes #76 6年前
  Henry D. Case b1d6c0aeaa Change function name verifyPeerCertificate->verifyPeerHandshakeSignature 6年前
  Henry D. Case 91d6db578b CI: Fail build if code is wrongly formatted 6年前
  Henry D. Case b6af4dd343 Code formatting for handshake_server_test.go 6年前
  Henry D. Case 3f720fc50c Code formatting for TRIS test client and server 6年前
26個のファイルの変更1233行の追加262行の削除
分割表示
  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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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 ファイルの表示

@@ -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)


読み込み中…
キャンセル
保存