sidh: adds PQ secure KEX
* SIDH/P503-X25519 * adds interop tests
This commit is contained in:
parent
7c79cbefc5
commit
d184bc0099
253
13.go
253
13.go
@ -21,6 +21,7 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
sidh "github_com/cloudflare/sidh/sidh"
|
||||
"golang_org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
@ -29,11 +30,16 @@ import (
|
||||
const numSessionTickets = 2
|
||||
|
||||
type secretLabel int
|
||||
type role uint8
|
||||
|
||||
const (
|
||||
kRole_Server = iota
|
||||
kRole_Client
|
||||
x25519SharedSecretSz = 32
|
||||
|
||||
P503PubKeySz = 378
|
||||
P503PrvKeySz = 32
|
||||
P503SharedSecretSz = 126
|
||||
SidhP503Curve25519PubKeySz = x25519SharedSecretSz + P503PubKeySz
|
||||
SidhP503Curve25519PrvKeySz = x25519SharedSecretSz + P503PrvKeySz
|
||||
SidhP503Curve25519SharedKeySz = x25519SharedSecretSz + P503SharedSecretSz
|
||||
)
|
||||
|
||||
const (
|
||||
@ -55,6 +61,38 @@ type keySchedule13 struct {
|
||||
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 {
|
||||
if config.KeyLogWriter == nil {
|
||||
clientRandom = nil
|
||||
@ -80,6 +118,15 @@ func (ks *keySchedule13) setSecret(secret []byte) {
|
||||
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.
|
||||
func (ks *keySchedule13) write(data []byte) {
|
||||
ks.handshakeCtx = nil
|
||||
@ -186,7 +233,7 @@ CurvePreferenceLoop:
|
||||
|
||||
earlyClientCipher, _ := hs.keySchedule.prepareCipher(secretEarlyClient)
|
||||
|
||||
ecdheSecret := c.deriveECDHESecret(ks, privateKey)
|
||||
ecdheSecret := c.deriveDHESecret(ks, privateKey)
|
||||
if ecdheSecret == nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: bad ECDHE client share")
|
||||
@ -551,61 +598,22 @@ func prepareDigitallySigned(hash crypto.Hash, context string, data []byte) []byt
|
||||
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) {
|
||||
if curveID == X25519 {
|
||||
var scalar, public [32]byte
|
||||
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
|
||||
if val, ok := dhKexStrat[curveID]; ok {
|
||||
return val.generate(c, curveID)
|
||||
}
|
||||
|
||||
curve, ok := curveForCurveID(curveID)
|
||||
if !ok {
|
||||
return nil, keyShare{}, errors.New("tls: preferredCurves includes unsupported curve")
|
||||
}
|
||||
|
||||
privateKey, x, y, err := elliptic.GenerateKey(curve, c.config.rand())
|
||||
if err != nil {
|
||||
return nil, keyShare{}, err
|
||||
}
|
||||
ecdhePublic := elliptic.Marshal(curve, x, y)
|
||||
|
||||
return privateKey, keyShare{group: curveID, data: ecdhePublic}, nil
|
||||
return nil, keyShare{}, errors.New("tls: preferredCurves includes unsupported curve")
|
||||
}
|
||||
|
||||
func (c *Conn) deriveECDHESecret(ks keyShare, secretKey []byte) []byte {
|
||||
if ks.group == X25519 {
|
||||
if len(ks.data) != 32 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var theirPublic, sharedKey, scalar [32]byte
|
||||
copy(theirPublic[:], ks.data)
|
||||
copy(scalar[:], secretKey)
|
||||
curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
|
||||
return sharedKey[:]
|
||||
// DH key agreement. ks stores public key, secretKey stores private key used for ephemeral
|
||||
// key agreement. Function returns shared secret in case of success or empty slice otherwise.
|
||||
func (c *Conn) deriveDHESecret(ks keyShare, secretKey []byte) []byte {
|
||||
if val, ok := dhKexStrat[ks.group]; ok {
|
||||
return val.derive(c, ks, secretKey)
|
||||
}
|
||||
|
||||
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
|
||||
return nil
|
||||
}
|
||||
|
||||
func hkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
|
||||
@ -981,7 +989,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
|
||||
|
||||
// 0-RTT is not supported yet, so use an empty PSK.
|
||||
hs.keySchedule.setSecret(nil)
|
||||
ecdheSecret := c.deriveECDHESecret(serverHello.keyShare, hs.privateKey)
|
||||
ecdheSecret := c.deriveDHESecret(serverHello.keyShare, hs.privateKey)
|
||||
if ecdheSecret == nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: bad ECDHE server share")
|
||||
@ -1161,3 +1169,138 @@ func supportedSigAlgorithmsCert(schemes []SignatureScheme) (ret []SignatureSchem
|
||||
}
|
||||
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)
|
||||
OS_ARCH := $(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)
|
||||
# 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))
|
||||
@ -30,8 +30,10 @@ BOGO_DOCKER_TRIS_LOCATION=/go/src/github.com/cloudflare/tls-tris
|
||||
|
||||
# SIDH repository (TODO: change path)
|
||||
SIDH_REPO ?= https://github.com/cloudflare/sidh.git
|
||||
SIDH_REPO_TAG ?= 25c0d9f15d5e5bd5652b9741aeb50d9eb37154dc
|
||||
# NOBS repo (SIKE depends on SHA3)
|
||||
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
|
||||
$(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
|
||||
cp -rf $(TMP_DIR)/nobs/tls_vendor/* $(GOROOT_LOCAL)/src/vendor/
|
||||
|
||||
# Vendor SIDH library
|
||||
$(GIT) clone $(SIDH_REPO) $(TMP_DIR)/sidh
|
||||
cd $(TMP_DIR)/sidh; $(GIT) checkout $(SIDH_REPO_TAG)
|
||||
cd $(TMP_DIR)/sidh; make 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
|
||||
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')
|
||||
print(res[1])
|
||||
res = self.d.run_client(self.CLIENT_NAME, self.server_ip+":1443 "+'-alpn-protos npn_proto')
|
||||
self.assertEqual(res[0], 0)
|
||||
self.assertIsNotNone(re.search(RE_PATTERN_ALPN, 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(
|
||||
@ -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")
|
||||
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__':
|
||||
unittest.main()
|
||||
|
@ -8,6 +8,7 @@ EXPOSE 3443
|
||||
EXPOSE 4443
|
||||
EXPOSE 5443
|
||||
EXPOSE 6443
|
||||
EXPOSE 7443
|
||||
|
||||
ADD tris-localserver /
|
||||
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: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:7443 -cert=ecdsa -qr=c & # Enables support for both - post-quantum and classical KEX algorithms
|
||||
|
||||
wait
|
||||
|
@ -55,6 +55,15 @@ func NewServer() *server {
|
||||
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() {
|
||||
var err error
|
||||
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_confirm := flag.Bool("rtt0ack", false, "0-RTT confirm")
|
||||
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()
|
||||
|
||||
s.Address = *arg_addr
|
||||
@ -162,6 +172,12 @@ func main() {
|
||||
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) {
|
||||
tlsConn := r.Context().Value(http.TLSConnContextKey).(*tls.Conn)
|
||||
|
||||
|
@ -51,6 +51,17 @@ func (c *Client) setMinMaxTLS(ver uint16) {
|
||||
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() {
|
||||
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++
|
||||
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")
|
||||
}
|
||||
|
||||
@ -93,13 +103,14 @@ func result() {
|
||||
|
||||
// Usage client args host:port
|
||||
func main() {
|
||||
var keylog_file string
|
||||
var keylog_file, qrAlgoName 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(&qrAlgoName, "qr", "", "Specifies qr algorithm from following list:\n[SIDH-P503-X25519, SIDH-P751-X448]")
|
||||
flag.Parse()
|
||||
if flag.NArg() != 1 {
|
||||
flag.Usage()
|
||||
@ -124,6 +135,21 @@ func main() {
|
||||
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 {
|
||||
var err error
|
||||
client_cert, err := tls.X509KeyPair([]byte(client_crt), []byte(client_key))
|
||||
@ -145,6 +171,7 @@ func main() {
|
||||
c.setMinMaxTLS(tls.VersionTLS12)
|
||||
c.run()
|
||||
}
|
||||
|
||||
if enable_ecdsa {
|
||||
// Sane cipher suite for TLS 1.2 with an ECDSA cert (as used by boringssl)
|
||||
c := client.clone()
|
||||
|
12
common.go
12
common.go
@ -116,10 +116,6 @@ const (
|
||||
type CurveID uint16
|
||||
|
||||
const (
|
||||
// Unexported
|
||||
sidhP503 CurveID = 0
|
||||
sidhP751 CurveID = 1
|
||||
|
||||
// Exported IDs
|
||||
CurveP256 CurveID = 23
|
||||
CurveP384 CurveID = 24
|
||||
@ -127,8 +123,12 @@ const (
|
||||
X25519 CurveID = 29
|
||||
|
||||
// Experimental KEX
|
||||
HybridSidhP503Curve25519 CurveID = 0x0105 + sidhP503 // HybridSIDH: X25519 + P503
|
||||
HybridSidhP751Curve448 CurveID = 0x0105 + sidhP751 // HybridSIDH: X448 + P751
|
||||
HybridSidhP503Curve25519 CurveID = 0x0105 + (sidhP503 & 0xFF) // HybridSIDH: X25519 + P503
|
||||
HybridSidhP751Curve448 CurveID = 0x0105 + (sidhP751 & 0xFF) // HybridSIDH: X448 + P751
|
||||
|
||||
// Internal usage. Deliberately not exported
|
||||
sidhP503 CurveID = 0xFE00
|
||||
sidhP751 CurveID = 0xFE01
|
||||
)
|
||||
|
||||
// TLS 1.3 Key Share
|
||||
|
Loading…
Reference in New Issue
Block a user