From 76231e7564d9925696cc5edd778c2ef6d151ad86 Mon Sep 17 00:00:00 2001 From: Kris Kwiatkowski Date: Fri, 7 Dec 2018 15:35:53 +0000 Subject: [PATCH] SIDH: Implement test againt TLSv1.2 Tris tries to connect to BoringSSL over TLS 1.2 with X25519-SIDH as prefered DH group. As this is not supported by BoringSSL it must fall back to P-256 (second preference on the list) Also refactors tris test client --- 13.go | 4 +- _dev/boring/Dockerfile | 2 +- _dev/boring/server.sh | 2 +- _dev/interop_test_runner | 15 ++++++- _dev/tris-testclient/client.go | 81 +++++++++++++++++++--------------- 5 files changed, 62 insertions(+), 42 deletions(-) diff --git a/13.go b/13.go index ed36be0..15a655c 100644 --- a/13.go +++ b/13.go @@ -1231,7 +1231,7 @@ func (kexSIDHp503) generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) return nil, keyShare{}, errors.New("tls: private SIDH key generation failed") } pubKey := prvKey.GeneratePublicKey() - return prvKey.Export(), keyShare{group: 0, data: pubKey.Export()}, nil + return prvKey.Export(), keyShare{group: 0 /*UNUSED*/, data: pubKey.Export()}, nil } func (kexSIDHp503) derive(c *Conn, ks keyShare, key []byte) []byte { @@ -1295,7 +1295,7 @@ func (kex *kexHybridSIDHp503X25519) derive(c *Conn, ks keyShare, key []byte) []b copy(sharedKey[:], ret) // Key agreement for PQ - tmpKs.group = 0 + tmpKs.group = 0 /*UNUSED*/ tmpKs.data = ks.data[x25519SharedSecretSz:] ret = kex.pqKEX.derive(c, tmpKs, key[x25519SharedSecretSz:]) if ret == nil { diff --git a/_dev/boring/Dockerfile b/_dev/boring/Dockerfile index 666492d..6e310f8 100644 --- a/_dev/boring/Dockerfile +++ b/_dev/boring/Dockerfile @@ -59,7 +59,7 @@ ADD sidh_$REVISION.patch / RUN cd boringssl && git fetch RUN cd boringssl && git checkout $REVISION RUN cd boringssl && patch -p1 < /sidh_$REVISION.patch -RUN cd boringssl/build && cmake -DEXP_SIDH=1 -GNinja .. +RUN cd boringssl/build && cmake -GNinja .. RUN cd boringssl && ninja -C build ADD httpreq.txt /httpreq.txt diff --git a/_dev/boring/server.sh b/_dev/boring/server.sh index 6fcf87f..7cad11f 100755 --- a/_dev/boring/server.sh +++ b/_dev/boring/server.sh @@ -25,7 +25,7 @@ bssl server \ bssl server \ -key ecdsa.pem \ -curves X25519-SIDHp503:X25519:P-256:P-384:P-521 \ - -min-version tls1.3 -max-version tls1.3 \ + -min-version tls1.2 -max-version tls1.3 \ -accept 7443 -loop -www \ -debug 2>&1 & diff --git a/_dev/interop_test_runner b/_dev/interop_test_runner index 60dce37..c1de46d 100755 --- a/_dev/interop_test_runner +++ b/_dev/interop_test_runner @@ -257,10 +257,21 @@ class InteropClient_BoringSSL(InteropClient, ClientNominalMixin, ClientClientAut ''' Connects to BoringSSL server listening on 7443 and tries to perform key agreement with SIDH/P503-X25519 ''' - res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr X25519-SIDHp503 ' + self.server_ip+":7443") + res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -groups X25519-SIDHp503 ' + self.server_ip+":7443") self.assertEqual(res[0], 0) self.assertIsNotNone(re.search(RE_TRIS_ALL_PASSED, res[1], re.MULTILINE)) + def test_SIDH_TLSv12(self): + ''' + Connects to TRIS server listening on 7443 and tries to perform key agreement with SIDH/P503-X25519 + This connection will be over TLSv12 and hence it should fall back to X25519 + ''' + res = self.d.run_client(self.CLIENT_NAME, '-tls_version=1.2 -rsa=false -ecdsa=true -groups X25519-SIDHp503:P-256 -ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ' + self.server_ip+":7443") + self.assertEqual(res[0], 0) + # Go doesn't provide API to get NamedGroup ID, but boringssl on port 7443 accepts only TLS1.2 + # so if handshake was successful, then that's all what we need + self.assertIsNotNone(re.search(RE_TRIS_ALL_PASSED, res[1], re.MULTILINE)) + class InteropClient_NSS( InteropClient, ClientNominalMixin, @@ -278,7 +289,7 @@ class InteropServer_TRIS(ClientNominalMixin, InteropServer, unittest.TestCase): self.assertEqual(res[0], 0) def test_SIDH(self): - res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr X25519-SIDHp503 '+self.server_ip+":7443") + res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -groups X25519-SIDHp503 '+self.server_ip+":7443") self.assertEqual(res[0], 0) def test_server_doesnt_support_SIDH(self): diff --git a/_dev/tris-testclient/client.go b/_dev/tris-testclient/client.go index aa2a5ca..938e098 100644 --- a/_dev/tris-testclient/client.go +++ b/_dev/tris-testclient/client.go @@ -3,6 +3,7 @@ package main import ( "crypto/tls" "crypto/x509" + "errors" "flag" "fmt" "io" @@ -26,6 +27,23 @@ var cipherSuiteIdToName = map[uint16]string{ tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", } +var namedGroupsToName = map[uint16]string{ + uint16(tls.HybridSIDHp503Curve25519): "X25519-SIDHp503", + uint16(tls.X25519): "X25519", + uint16(tls.CurveP256): "P-256", + uint16(tls.CurveP384): "P-384", + uint16(tls.CurveP521): "P-521", +} + +func getIDByName(m map[uint16]string, name string) (uint16, error) { + for key, value := range m { + if value == name { + return key, nil + } + } + return 0, errors.New("Unknown value") +} + var failed uint type Client struct { @@ -51,15 +69,6 @@ func (c *Client) setMinMaxTLS(ver uint16) { c.TLS.MaxVersion = ver } -func getQrAlgoId(qr string) tls.CurveID { - switch qr { - case "X25519-SIDHp503": - return tls.HybridSIDHp503Curve25519 - default: - return 0 - } -} - func (c *Client) run() { fmt.Printf("TLS %s with %s\n", tlsVersionToName[c.TLS.MinVersion], cipherSuiteIdToName[c.TLS.CipherSuites[0]]) @@ -101,14 +110,16 @@ func result() { // Usage client args host:port func main() { - var keylog_file, qrAlgoName string + var keylog_file, tls_version, named_groups, named_ciphers 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[X25519-SIDHp503]") + flag.StringVar(&tls_version, "tls_version", "1.3", "TLS version to use") + flag.StringVar(&named_groups, "groups", "X25519:P-256:P-384:P-521", "NamedGroups IDs to use") + flag.StringVar(&named_ciphers, "ciphers", "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384", "Named cipher IDs to use") flag.Parse() if flag.NArg() != 1 { flag.Usage() @@ -133,21 +144,6 @@ 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)) @@ -178,17 +174,30 @@ func main() { c.run() } - client.setMinMaxTLS(tls.VersionTLS13) - client.TLS.CipherSuites = []uint16{tls.TLS_CHACHA20_POLY1305_SHA256} - client.run() + // Set requested DH groups + client.TLS.CurvePreferences = []tls.CurveID{} + for _, ng := range strings.Split(named_groups, ":") { + id, err := getIDByName(namedGroupsToName, ng) + if err != nil { + panic("Wrong TLS version provided") + } + client.TLS.CurvePreferences = append(client.TLS.CurvePreferences, tls.CurveID(id)) + } - 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() + // Perform TLS handshake with each each requested CipherSuite + tlsID, err := getIDByName(tlsVersionToName, tls_version) + if err != nil { + panic("Unknown TLS version") + } + for _, cn := range strings.Split(named_ciphers, ":") { + id, err := getIDByName(cipherSuiteIdToName, cn) + if err != nil { + panic("Wrong cipher name provided") + } + client.setMinMaxTLS(tlsID) + client.TLS.CipherSuites = []uint16{id} + client.run() + } // TODO test other kex methods besides X25519, like MTI secp256r1 // TODO limit supported groups?