sidh: adds PQ secure KEX
* SIDH/P503-X25519 * adds interop tests
This commit is contained in:
parent
7c79cbefc5
commit
d184bc0099
249
13.go
249
13.go
@ -21,6 +21,7 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
sidh "github_com/cloudflare/sidh/sidh"
|
||||||
"golang_org/x/crypto/curve25519"
|
"golang_org/x/crypto/curve25519"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,11 +30,16 @@ import (
|
|||||||
const numSessionTickets = 2
|
const numSessionTickets = 2
|
||||||
|
|
||||||
type secretLabel int
|
type secretLabel int
|
||||||
type role uint8
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
kRole_Server = iota
|
x25519SharedSecretSz = 32
|
||||||
kRole_Client
|
|
||||||
|
P503PubKeySz = 378
|
||||||
|
P503PrvKeySz = 32
|
||||||
|
P503SharedSecretSz = 126
|
||||||
|
SidhP503Curve25519PubKeySz = x25519SharedSecretSz + P503PubKeySz
|
||||||
|
SidhP503Curve25519PrvKeySz = x25519SharedSecretSz + P503PrvKeySz
|
||||||
|
SidhP503Curve25519SharedKeySz = x25519SharedSecretSz + P503SharedSecretSz
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -55,6 +61,38 @@ type keySchedule13 struct {
|
|||||||
config *Config // Used for KeyLogWriter callback, nil if keylogging is disabled.
|
config *Config // Used for KeyLogWriter callback, nil if keylogging is disabled.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interface implemented by DH key exchange strategies
|
||||||
|
type dhKex interface {
|
||||||
|
// c - context of current TLS handshake, groupId - ID of an algorithm
|
||||||
|
// (curve/field) being chosen for key agreement. Methods implmenting an
|
||||||
|
// interface always assume that provided groupId is correct.
|
||||||
|
//
|
||||||
|
// In case of success, function returns secret key and ephemeral key. Otherwise
|
||||||
|
// error is set.
|
||||||
|
generate(c *Conn, groupId CurveID) ([]byte, keyShare, error)
|
||||||
|
// c - context of current TLS handshake, ks - public key received
|
||||||
|
// from the other side of the connection, secretKey - is a private key
|
||||||
|
// used for DH key agreement. Function returns shared secret in case
|
||||||
|
// of success or empty slice otherwise.
|
||||||
|
derive(c *Conn, ks keyShare, secretKey []byte) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key Exchange strategies per curve type
|
||||||
|
type kexNist struct{} // Used by NIST curves; P-256, P-384, P-512
|
||||||
|
type kexX25519 struct{} // Used by X25519
|
||||||
|
type kexSidhP503 struct{} // Used by SIDH/P503
|
||||||
|
type kexHybridSidhP503X25519 struct{} // Used by SIDH-ECDH hybrid scheme
|
||||||
|
|
||||||
|
// Routing map for key exchange strategies
|
||||||
|
var dhKexStrat = map[CurveID]dhKex{
|
||||||
|
CurveP256: &kexNist{},
|
||||||
|
CurveP384: &kexNist{},
|
||||||
|
CurveP521: &kexNist{},
|
||||||
|
X25519: &kexX25519{},
|
||||||
|
sidhP503: &kexSidhP503{},
|
||||||
|
HybridSidhP503Curve25519: &kexHybridSidhP503X25519{},
|
||||||
|
}
|
||||||
|
|
||||||
func newKeySchedule13(suite *cipherSuite, config *Config, clientRandom []byte) *keySchedule13 {
|
func newKeySchedule13(suite *cipherSuite, config *Config, clientRandom []byte) *keySchedule13 {
|
||||||
if config.KeyLogWriter == nil {
|
if config.KeyLogWriter == nil {
|
||||||
clientRandom = nil
|
clientRandom = nil
|
||||||
@ -80,6 +118,15 @@ func (ks *keySchedule13) setSecret(secret []byte) {
|
|||||||
ks.secret = hkdfExtract(hash, secret, salt)
|
ks.secret = hkdfExtract(hash, secret, salt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Depending on role returns pair of key variant to be used by
|
||||||
|
// local and remote process.
|
||||||
|
func getSidhKeyVariant(isClient bool) (sidh.KeyVariant, sidh.KeyVariant) {
|
||||||
|
if isClient {
|
||||||
|
return sidh.KeyVariant_SIDH_A, sidh.KeyVariant_SIDH_B
|
||||||
|
}
|
||||||
|
return sidh.KeyVariant_SIDH_B, sidh.KeyVariant_SIDH_A
|
||||||
|
}
|
||||||
|
|
||||||
// write appends the data to the transcript hash context.
|
// write appends the data to the transcript hash context.
|
||||||
func (ks *keySchedule13) write(data []byte) {
|
func (ks *keySchedule13) write(data []byte) {
|
||||||
ks.handshakeCtx = nil
|
ks.handshakeCtx = nil
|
||||||
@ -186,7 +233,7 @@ CurvePreferenceLoop:
|
|||||||
|
|
||||||
earlyClientCipher, _ := hs.keySchedule.prepareCipher(secretEarlyClient)
|
earlyClientCipher, _ := hs.keySchedule.prepareCipher(secretEarlyClient)
|
||||||
|
|
||||||
ecdheSecret := c.deriveECDHESecret(ks, privateKey)
|
ecdheSecret := c.deriveDHESecret(ks, privateKey)
|
||||||
if ecdheSecret == nil {
|
if ecdheSecret == nil {
|
||||||
c.sendAlert(alertIllegalParameter)
|
c.sendAlert(alertIllegalParameter)
|
||||||
return errors.New("tls: bad ECDHE client share")
|
return errors.New("tls: bad ECDHE client share")
|
||||||
@ -551,63 +598,24 @@ func prepareDigitallySigned(hash crypto.Hash, context string, data []byte) []byt
|
|||||||
return h.Sum(nil)
|
return h.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 *Conn) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
|
func (c *Conn) generateKeyShare(curveID CurveID) ([]byte, keyShare, error) {
|
||||||
if curveID == X25519 {
|
if val, ok := dhKexStrat[curveID]; ok {
|
||||||
var scalar, public [32]byte
|
return val.generate(c, curveID)
|
||||||
if _, err := io.ReadFull(c.config.rand(), scalar[:]); err != nil {
|
|
||||||
return nil, keyShare{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curve25519.ScalarBaseMult(&public, &scalar)
|
|
||||||
return scalar[:], keyShare{group: curveID, data: public[:]}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
curve, ok := curveForCurveID(curveID)
|
|
||||||
if !ok {
|
|
||||||
return nil, keyShare{}, errors.New("tls: preferredCurves includes unsupported curve")
|
return nil, keyShare{}, errors.New("tls: preferredCurves includes unsupported curve")
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey, x, y, err := elliptic.GenerateKey(curve, c.config.rand())
|
// DH key agreement. ks stores public key, secretKey stores private key used for ephemeral
|
||||||
if err != nil {
|
// key agreement. Function returns shared secret in case of success or empty slice otherwise.
|
||||||
return nil, keyShare{}, err
|
func (c *Conn) deriveDHESecret(ks keyShare, secretKey []byte) []byte {
|
||||||
|
if val, ok := dhKexStrat[ks.group]; ok {
|
||||||
|
return val.derive(c, ks, secretKey)
|
||||||
}
|
}
|
||||||
ecdhePublic := elliptic.Marshal(curve, x, y)
|
|
||||||
|
|
||||||
return privateKey, keyShare{group: curveID, data: ecdhePublic}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) deriveECDHESecret(ks keyShare, secretKey []byte) []byte {
|
|
||||||
if ks.group == X25519 {
|
|
||||||
if len(ks.data) != 32 {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var theirPublic, sharedKey, scalar [32]byte
|
|
||||||
copy(theirPublic[:], ks.data)
|
|
||||||
copy(scalar[:], secretKey)
|
|
||||||
curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
|
|
||||||
return sharedKey[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
curve, ok := curveForCurveID(ks.group)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
x, y := elliptic.Unmarshal(curve, ks.data)
|
|
||||||
if x == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
x, _ = curve.ScalarMult(x, y, secretKey)
|
|
||||||
xBytes := x.Bytes()
|
|
||||||
curveSize := (curve.Params().BitSize + 8 - 1) >> 3
|
|
||||||
if len(xBytes) == curveSize {
|
|
||||||
return xBytes
|
|
||||||
}
|
|
||||||
buf := make([]byte, curveSize)
|
|
||||||
copy(buf[len(buf)-len(xBytes):], xBytes)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func hkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
|
func hkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
|
||||||
prefix := "tls13 "
|
prefix := "tls13 "
|
||||||
hkdfLabel := make([]byte, 4+len(prefix)+len(label)+len(hashValue))
|
hkdfLabel := make([]byte, 4+len(prefix)+len(label)+len(hashValue))
|
||||||
@ -981,7 +989,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
|
|||||||
|
|
||||||
// 0-RTT is not supported yet, so use an empty PSK.
|
// 0-RTT is not supported yet, so use an empty PSK.
|
||||||
hs.keySchedule.setSecret(nil)
|
hs.keySchedule.setSecret(nil)
|
||||||
ecdheSecret := c.deriveECDHESecret(serverHello.keyShare, hs.privateKey)
|
ecdheSecret := c.deriveDHESecret(serverHello.keyShare, hs.privateKey)
|
||||||
if ecdheSecret == nil {
|
if ecdheSecret == nil {
|
||||||
c.sendAlert(alertIllegalParameter)
|
c.sendAlert(alertIllegalParameter)
|
||||||
return errors.New("tls: bad ECDHE server share")
|
return errors.New("tls: bad ECDHE server share")
|
||||||
@ -1161,3 +1169,138 @@ func supportedSigAlgorithmsCert(schemes []SignatureScheme) (ret []SignatureSchem
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Functions below implement dhKex interface for different DH shared secret agreements
|
||||||
|
|
||||||
|
// KEX: P-256, P-384, P-512 KEX
|
||||||
|
func (kexNist) generate(c *Conn, groupId CurveID) (private []byte, ks keyShare, err error) {
|
||||||
|
// never fails
|
||||||
|
curve, _ := curveForCurveID(groupId)
|
||||||
|
private, x, y, err := elliptic.GenerateKey(curve, c.config.rand())
|
||||||
|
if err != nil {
|
||||||
|
return nil, keyShare{}, err
|
||||||
|
}
|
||||||
|
ks.group = groupId
|
||||||
|
ks.data = elliptic.Marshal(curve, x, y)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (kexNist) derive(c *Conn, ks keyShare, secretKey []byte) []byte {
|
||||||
|
// never fails
|
||||||
|
curve, _ := curveForCurveID(ks.group)
|
||||||
|
x, y := elliptic.Unmarshal(curve, ks.data)
|
||||||
|
if x == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
x, _ = curve.ScalarMult(x, y, secretKey)
|
||||||
|
xBytes := x.Bytes()
|
||||||
|
curveSize := (curve.Params().BitSize + 8 - 1) >> 3
|
||||||
|
if len(xBytes) == curveSize {
|
||||||
|
return xBytes
|
||||||
|
}
|
||||||
|
buf := make([]byte, curveSize)
|
||||||
|
copy(buf[len(buf)-len(xBytes):], xBytes)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
// KEX: X25519
|
||||||
|
func (kexX25519) generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) {
|
||||||
|
var scalar, public [x25519SharedSecretSz]byte
|
||||||
|
if _, err := io.ReadFull(c.config.rand(), scalar[:]); err != nil {
|
||||||
|
return nil, keyShare{}, err
|
||||||
|
}
|
||||||
|
curve25519.ScalarBaseMult(&public, &scalar)
|
||||||
|
return scalar[:], keyShare{group: X25519, data: public[:]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kexX25519) derive(c *Conn, ks keyShare, secretKey []byte) []byte {
|
||||||
|
var theirPublic, sharedKey, scalar [x25519SharedSecretSz]byte
|
||||||
|
if len(ks.data) != x25519SharedSecretSz {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
copy(theirPublic[:], ks.data)
|
||||||
|
copy(scalar[:], secretKey)
|
||||||
|
curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
|
||||||
|
return sharedKey[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// KEX: SIDH/503
|
||||||
|
func (kexSidhP503) generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) {
|
||||||
|
var variant, _ = getSidhKeyVariant(c.isClient)
|
||||||
|
var prvKey = sidh.NewPrivateKey(sidh.FP_503, variant)
|
||||||
|
if prvKey.Generate(c.config.rand()) != nil {
|
||||||
|
return nil, keyShare{}, errors.New("tls: private SIDH key generation failed")
|
||||||
|
}
|
||||||
|
pubKey := prvKey.GeneratePublicKey()
|
||||||
|
return prvKey.Export(), keyShare{group: sidhP503, data: pubKey.Export()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kexSidhP503) derive(c *Conn, ks keyShare, key []byte) []byte {
|
||||||
|
var prvVariant, pubVariant = getSidhKeyVariant(c.isClient)
|
||||||
|
var prvKeySize = P503PrvKeySz
|
||||||
|
|
||||||
|
if len(ks.data) != P503PubKeySz || len(key) != prvKeySize {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
prvKey := sidh.NewPrivateKey(sidh.FP_503, prvVariant)
|
||||||
|
pubKey := sidh.NewPublicKey(sidh.FP_503, pubVariant)
|
||||||
|
|
||||||
|
if err := prvKey.Import(key); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := pubKey.Import(ks.data); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never fails
|
||||||
|
sharedKey, _ := sidh.DeriveSecret(prvKey, pubKey)
|
||||||
|
return sharedKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// KEX Hybrid SIDH/503-X25519
|
||||||
|
func (kexHybridSidhP503X25519) generate(c *Conn, groupId CurveID) (private []byte, ks keyShare, err error) {
|
||||||
|
var pubHybrid [SidhP503Curve25519PubKeySz]byte
|
||||||
|
var prvHybrid [SidhP503Curve25519PrvKeySz]byte
|
||||||
|
|
||||||
|
// Generate ephemeral key for classic x25519
|
||||||
|
private, ks, err = dhKexStrat[X25519].generate(c, groupId)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(prvHybrid[:], private)
|
||||||
|
copy(pubHybrid[:], ks.data)
|
||||||
|
|
||||||
|
// Generate PQ ephemeral key for SIDH
|
||||||
|
private, ks, err = dhKexStrat[sidhP503].generate(c, groupId)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(prvHybrid[x25519SharedSecretSz:], private)
|
||||||
|
copy(pubHybrid[x25519SharedSecretSz:], ks.data)
|
||||||
|
return prvHybrid[:], keyShare{group: HybridSidhP503Curve25519, data: pubHybrid[:]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kexHybridSidhP503X25519) derive(c *Conn, ks keyShare, key []byte) []byte {
|
||||||
|
var sharedKey [SidhP503Curve25519SharedKeySz]byte
|
||||||
|
var ret []byte
|
||||||
|
var tmpKs keyShare
|
||||||
|
|
||||||
|
// Key agreement for classic
|
||||||
|
tmpKs.group = X25519
|
||||||
|
tmpKs.data = ks.data[:x25519SharedSecretSz]
|
||||||
|
ret = dhKexStrat[X25519].derive(c, tmpKs, key[:x25519SharedSecretSz])
|
||||||
|
if ret == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
copy(sharedKey[:], ret)
|
||||||
|
|
||||||
|
// Key agreement for PQ
|
||||||
|
tmpKs.group = sidhP503
|
||||||
|
tmpKs.data = ks.data[x25519SharedSecretSz:]
|
||||||
|
ret = dhKexStrat[sidhP503].derive(c, tmpKs, key[x25519SharedSecretSz:])
|
||||||
|
if ret == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
copy(sharedKey[x25519SharedSecretSz:], ret)
|
||||||
|
return sharedKey[:]
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ OS ?= $(shell $(GO) env GOHOSTOS)
|
|||||||
ARCH ?= $(shell $(GO) env GOHOSTARCH)
|
ARCH ?= $(shell $(GO) env GOHOSTARCH)
|
||||||
OS_ARCH := $(OS)_$(ARCH)
|
OS_ARCH := $(OS)_$(ARCH)
|
||||||
VER_OS_ARCH := $(shell $(GO) version | cut -d' ' -f 3)_$(OS)_$(ARCH)
|
VER_OS_ARCH := $(shell $(GO) version | cut -d' ' -f 3)_$(OS)_$(ARCH)
|
||||||
GOROOT_ENV := $(shell $(GO) env GOROOT)
|
GOROOT_ENV ?= $(shell $(GO) env GOROOT)
|
||||||
GOROOT_LOCAL = $(BUILD_DIR)/$(OS_ARCH)
|
GOROOT_LOCAL = $(BUILD_DIR)/$(OS_ARCH)
|
||||||
# Flag indicates wheter invoke "go install -race std". Supported only on amd64 with CGO enabled
|
# 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))
|
INSTALL_RACE:= $(words $(filter $(ARCH)_$(shell go env CGO_ENABLED), amd64_1))
|
||||||
@ -30,8 +30,10 @@ BOGO_DOCKER_TRIS_LOCATION=/go/src/github.com/cloudflare/tls-tris
|
|||||||
|
|
||||||
# SIDH repository (TODO: change path)
|
# SIDH repository (TODO: change path)
|
||||||
SIDH_REPO ?= https://github.com/cloudflare/sidh.git
|
SIDH_REPO ?= https://github.com/cloudflare/sidh.git
|
||||||
|
SIDH_REPO_TAG ?= 25c0d9f15d5e5bd5652b9741aeb50d9eb37154dc
|
||||||
# NOBS repo (SIKE depends on SHA3)
|
# NOBS repo (SIKE depends on SHA3)
|
||||||
NOBS_REPO ?= https://github.com/henrydcase/nobscrypto.git
|
NOBS_REPO ?= https://github.com/henrydcase/nobscrypto.git
|
||||||
|
NOBS_REPO_TAG ?= 597f68906e981e61160b8c959b326596c0b240be
|
||||||
|
|
||||||
###############
|
###############
|
||||||
#
|
#
|
||||||
@ -57,11 +59,13 @@ $(BUILD_DIR)/$(OS_ARCH)/.ok_$(VER_OS_ARCH): clean
|
|||||||
|
|
||||||
# Vendor NOBS library
|
# Vendor NOBS library
|
||||||
$(GIT) clone $(NOBS_REPO) $(TMP_DIR)/nobs
|
$(GIT) clone $(NOBS_REPO) $(TMP_DIR)/nobs
|
||||||
|
cd $(TMP_DIR)/nobs; $(GIT) checkout $(NOBS_REPO_TAG)
|
||||||
cd $(TMP_DIR)/nobs; make vendor-sidh-for-tls
|
cd $(TMP_DIR)/nobs; make vendor-sidh-for-tls
|
||||||
cp -rf $(TMP_DIR)/nobs/tls_vendor/* $(GOROOT_LOCAL)/src/vendor/
|
cp -rf $(TMP_DIR)/nobs/tls_vendor/* $(GOROOT_LOCAL)/src/vendor/
|
||||||
|
|
||||||
# Vendor SIDH library
|
# Vendor SIDH library
|
||||||
$(GIT) clone $(SIDH_REPO) $(TMP_DIR)/sidh
|
$(GIT) clone $(SIDH_REPO) $(TMP_DIR)/sidh
|
||||||
|
cd $(TMP_DIR)/sidh; $(GIT) checkout $(SIDH_REPO_TAG)
|
||||||
cd $(TMP_DIR)/sidh; make vendor
|
cd $(TMP_DIR)/sidh; make vendor
|
||||||
cp -rf $(TMP_DIR)/sidh/build/vendor/* $(GOROOT_LOCAL)/src/vendor/
|
cp -rf $(TMP_DIR)/sidh/build/vendor/* $(GOROOT_LOCAL)/src/vendor/
|
||||||
|
|
||||||
|
@ -216,12 +216,10 @@ class InteropServer_BoringSSL(InteropServer, ServerNominalMixin, ServerClientAut
|
|||||||
Checks wether ALPN is sent back by tris server in EncryptedExtensions in case of TLS 1.3. The
|
Checks wether ALPN is sent back by tris server in EncryptedExtensions in case of TLS 1.3. The
|
||||||
ALPN protocol is set to 'npn_proto', which is hardcoded in TRIS test server.
|
ALPN protocol is set to 'npn_proto', which is hardcoded in TRIS test server.
|
||||||
'''
|
'''
|
||||||
res = self.d.run_client(self.CLIENT_NAME, self.server_ip+":1443 "+'-alpn-protos npn_proto -debug')
|
res = self.d.run_client(self.CLIENT_NAME, self.server_ip+":1443 "+'-alpn-protos npn_proto')
|
||||||
print(res[1])
|
|
||||||
self.assertEqual(res[0], 0)
|
self.assertEqual(res[0], 0)
|
||||||
self.assertIsNotNone(re.search(RE_PATTERN_ALPN, res[1], re.MULTILINE))
|
self.assertIsNotNone(re.search(RE_PATTERN_ALPN, res[1], re.MULTILINE))
|
||||||
|
|
||||||
|
|
||||||
# PicoTLS doesn't seem to implement draft-23 correctly. It will
|
# PicoTLS doesn't seem to implement draft-23 correctly. It will
|
||||||
# be enabled when draft-28 is implemented.
|
# be enabled when draft-28 is implemented.
|
||||||
# class InteropServer_PicoTLS(
|
# class InteropServer_PicoTLS(
|
||||||
@ -262,5 +260,17 @@ class InteropServer_TRIS(ClientNominalMixin, InteropServer, unittest.TestCase):
|
|||||||
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=false -cliauth '+self.server_ip+":6443")
|
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=false -cliauth '+self.server_ip+":6443")
|
||||||
self.assertEqual(res[0], 0)
|
self.assertEqual(res[0], 0)
|
||||||
|
|
||||||
|
def test_qr(self):
|
||||||
|
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr SIDH-P503-X25519 '+self.server_ip+":7443")
|
||||||
|
self.assertEqual(res[0], 0)
|
||||||
|
|
||||||
|
def test_qrServerDoesntSupportSIDH(self):
|
||||||
|
'''
|
||||||
|
Client advertises HybridSIDH and ECDH. Server supports ECDH only. Checks weather
|
||||||
|
TLS session can still be established.
|
||||||
|
'''
|
||||||
|
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true '+self.server_ip+":7443")
|
||||||
|
self.assertEqual(res[0], 0)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -8,6 +8,7 @@ EXPOSE 3443
|
|||||||
EXPOSE 4443
|
EXPOSE 4443
|
||||||
EXPOSE 5443
|
EXPOSE 5443
|
||||||
EXPOSE 6443
|
EXPOSE 6443
|
||||||
|
EXPOSE 7443
|
||||||
|
|
||||||
ADD tris-localserver /
|
ADD tris-localserver /
|
||||||
ADD runner.sh /
|
ADD runner.sh /
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
./tris-localserver -b 0.0.0.0:4443 -cert=ecdsa -rtt0=oa 2>&1 & # fourth port: offer and accept 0-RTT
|
./tris-localserver -b 0.0.0.0:4443 -cert=ecdsa -rtt0=oa 2>&1 & # fourth port: offer and accept 0-RTT
|
||||||
./tris-localserver -b 0.0.0.0:5443 -cert=ecdsa -rtt0=oa -rtt0ack 2>&1 & # fifth port: offer and accept 0-RTT but confirm
|
./tris-localserver -b 0.0.0.0:5443 -cert=ecdsa -rtt0=oa -rtt0ack 2>&1 & # fifth port: offer and accept 0-RTT but confirm
|
||||||
./tris-localserver -b 0.0.0.0:6443 -cert=rsa -cliauth 2>&1 & # sixth port: RSA with required client authentication
|
./tris-localserver -b 0.0.0.0:6443 -cert=rsa -cliauth 2>&1 & # sixth port: RSA with required client authentication
|
||||||
|
./tris-localserver -b 0.0.0.0:7443 -cert=ecdsa -qr=c & # Enables support for both - post-quantum and classical KEX algorithms
|
||||||
|
|
||||||
wait
|
wait
|
||||||
|
@ -55,6 +55,15 @@ func NewServer() *server {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enableQR(s *server, enableDefault bool) {
|
||||||
|
var sidhCurves = []tls.CurveID{tls.HybridSidhP503Curve25519}
|
||||||
|
if enableDefault {
|
||||||
|
var defaultCurvePreferences = []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384, tls.CurveP521}
|
||||||
|
s.TLS.CurvePreferences = append(s.TLS.CurvePreferences, defaultCurvePreferences...)
|
||||||
|
}
|
||||||
|
s.TLS.CurvePreferences = append(s.TLS.CurvePreferences, sidhCurves...)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *server) start() {
|
func (s *server) start() {
|
||||||
var err error
|
var err error
|
||||||
if (s.ZeroRTT & ZeroRTT_Offer) == ZeroRTT_Offer {
|
if (s.ZeroRTT & ZeroRTT_Offer) == ZeroRTT_Offer {
|
||||||
@ -144,6 +153,7 @@ func main() {
|
|||||||
arg_zerortt := flag.String("rtt0", "n", `0-RTT, accepts following values [n: None, a: Accept, o: Offer, oa: Offer and Accept]`)
|
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_confirm := flag.Bool("rtt0ack", false, "0-RTT confirm")
|
||||||
arg_clientauth := flag.Bool("cliauth", false, "Performs client authentication (RequireAndVerifyClientCert used)")
|
arg_clientauth := flag.Bool("cliauth", false, "Performs client authentication (RequireAndVerifyClientCert used)")
|
||||||
|
arg_qr := flag.String("qr", "", "Enable quantum-resistant algorithms [c: Support classical and Quantum-Resistant, q: Enable Quantum-Resistant only]")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
s.Address = *arg_addr
|
s.Address = *arg_addr
|
||||||
@ -162,6 +172,12 @@ func main() {
|
|||||||
s.TLS.ClientAuth = tls.RequireAndVerifyClientCert
|
s.TLS.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *arg_qr == "c" {
|
||||||
|
enableQR(s, true)
|
||||||
|
} else if *arg_qr == "q" {
|
||||||
|
enableQR(s, false)
|
||||||
|
}
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
tlsConn := r.Context().Value(http.TLSConnContextKey).(*tls.Conn)
|
tlsConn := r.Context().Value(http.TLSConnContextKey).(*tls.Conn)
|
||||||
|
|
||||||
|
@ -51,6 +51,17 @@ func (c *Client) setMinMaxTLS(ver uint16) {
|
|||||||
c.TLS.MaxVersion = ver
|
c.TLS.MaxVersion = ver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getQrAlgoId(qr string) tls.CurveID {
|
||||||
|
switch qr {
|
||||||
|
case "SIDH-P503-X25519":
|
||||||
|
return tls.HybridSidhP503Curve25519
|
||||||
|
case "SIDH-P751-X448":
|
||||||
|
return tls.HybridSidhP751Curve448
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) run() {
|
func (c *Client) run() {
|
||||||
fmt.Printf("TLS %s with %s\n", tlsVersionToName[c.TLS.MinVersion], cipherSuiteIdToName[c.TLS.CipherSuites[0]])
|
fmt.Printf("TLS %s with %s\n", tlsVersionToName[c.TLS.MinVersion], cipherSuiteIdToName[c.TLS.CipherSuites[0]])
|
||||||
|
|
||||||
@ -78,8 +89,7 @@ func (c *Client) run() {
|
|||||||
failed++
|
failed++
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("Read %d bytes\n", n)
|
fmt.Printf("[TLS: %s] Read %d bytes\n", tlsVersionToName[con.ConnectionState().Version], n)
|
||||||
|
|
||||||
fmt.Println("OK\n")
|
fmt.Println("OK\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +103,14 @@ func result() {
|
|||||||
|
|
||||||
// Usage client args host:port
|
// Usage client args host:port
|
||||||
func main() {
|
func main() {
|
||||||
var keylog_file string
|
var keylog_file, qrAlgoName string
|
||||||
var enable_rsa, enable_ecdsa, client_auth bool
|
var enable_rsa, enable_ecdsa, client_auth bool
|
||||||
|
|
||||||
flag.StringVar(&keylog_file, "keylogfile", "", "Secrets will be logged here")
|
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_rsa, "rsa", true, "Whether to enable RSA cipher suites")
|
||||||
flag.BoolVar(&enable_ecdsa, "ecdsa", true, "Whether to enable ECDSA 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.BoolVar(&client_auth, "cliauth", false, "Whether to enable client authentication")
|
||||||
|
flag.StringVar(&qrAlgoName, "qr", "", "Specifies qr algorithm from following list:\n[SIDH-P503-X25519, SIDH-P751-X448]")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if flag.NArg() != 1 {
|
if flag.NArg() != 1 {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
@ -124,6 +135,21 @@ func main() {
|
|||||||
log.Println("Enabled keylog")
|
log.Println("Enabled keylog")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(qrAlgoName) > 0 {
|
||||||
|
id := getQrAlgoId(qrAlgoName)
|
||||||
|
if id == 0 {
|
||||||
|
log.Fatalf("Unknown QR algorithm: %s", qrAlgoName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client.TLS.CipherSuites = []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
|
||||||
|
client.TLS.CurvePreferences = []tls.CurveID{id}
|
||||||
|
client.setMinMaxTLS(tls.VersionTLS13)
|
||||||
|
client.run()
|
||||||
|
result()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if client_auth {
|
if client_auth {
|
||||||
var err error
|
var err error
|
||||||
client_cert, err := tls.X509KeyPair([]byte(client_crt), []byte(client_key))
|
client_cert, err := tls.X509KeyPair([]byte(client_crt), []byte(client_key))
|
||||||
@ -145,6 +171,7 @@ func main() {
|
|||||||
c.setMinMaxTLS(tls.VersionTLS12)
|
c.setMinMaxTLS(tls.VersionTLS12)
|
||||||
c.run()
|
c.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
if enable_ecdsa {
|
if enable_ecdsa {
|
||||||
// Sane cipher suite for TLS 1.2 with an ECDSA cert (as used by boringssl)
|
// Sane cipher suite for TLS 1.2 with an ECDSA cert (as used by boringssl)
|
||||||
c := client.clone()
|
c := client.clone()
|
||||||
|
12
common.go
12
common.go
@ -116,10 +116,6 @@ const (
|
|||||||
type CurveID uint16
|
type CurveID uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Unexported
|
|
||||||
sidhP503 CurveID = 0
|
|
||||||
sidhP751 CurveID = 1
|
|
||||||
|
|
||||||
// Exported IDs
|
// Exported IDs
|
||||||
CurveP256 CurveID = 23
|
CurveP256 CurveID = 23
|
||||||
CurveP384 CurveID = 24
|
CurveP384 CurveID = 24
|
||||||
@ -127,8 +123,12 @@ const (
|
|||||||
X25519 CurveID = 29
|
X25519 CurveID = 29
|
||||||
|
|
||||||
// Experimental KEX
|
// Experimental KEX
|
||||||
HybridSidhP503Curve25519 CurveID = 0x0105 + sidhP503 // HybridSIDH: X25519 + P503
|
HybridSidhP503Curve25519 CurveID = 0x0105 + (sidhP503 & 0xFF) // HybridSIDH: X25519 + P503
|
||||||
HybridSidhP751Curve448 CurveID = 0x0105 + sidhP751 // HybridSIDH: X448 + P751
|
HybridSidhP751Curve448 CurveID = 0x0105 + (sidhP751 & 0xFF) // HybridSIDH: X448 + P751
|
||||||
|
|
||||||
|
// Internal usage. Deliberately not exported
|
||||||
|
sidhP503 CurveID = 0xFE00
|
||||||
|
sidhP751 CurveID = 0xFE01
|
||||||
)
|
)
|
||||||
|
|
||||||
// TLS 1.3 Key Share
|
// TLS 1.3 Key Share
|
||||||
|
Loading…
Reference in New Issue
Block a user