@@ -37,9 +37,9 @@ const ( | |||||
P503PubKeySz = 378 | P503PubKeySz = 378 | ||||
P503PrvKeySz = 32 | P503PrvKeySz = 32 | ||||
P503SharedSecretSz = 126 | P503SharedSecretSz = 126 | ||||
SidhP503Curve25519PubKeySz = x25519SharedSecretSz + P503PubKeySz | |||||
SidhP503Curve25519PrvKeySz = x25519SharedSecretSz + P503PrvKeySz | |||||
SidhP503Curve25519SharedKeySz = x25519SharedSecretSz + P503SharedSecretSz | |||||
SIDHp503Curve25519PubKeySz = x25519SharedSecretSz + P503PubKeySz | |||||
SIDHp503Curve25519PrvKeySz = x25519SharedSecretSz + P503PrvKeySz | |||||
SIDHp503Curve25519SharedKeySz = x25519SharedSecretSz + P503SharedSecretSz | |||||
) | ) | ||||
const ( | const ( | ||||
@@ -78,10 +78,13 @@ type dhKex interface { | |||||
} | } | ||||
// Key Exchange strategies per curve type | // 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 | |||||
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 { | |||||
classicKEX kexX25519 | |||||
pqKEX kexSIDHp503 | |||||
} // Used by SIDH-ECDH hybrid scheme | |||||
// Routing map for key exchange strategies | // Routing map for key exchange strategies | ||||
var dhKexStrat = map[CurveID]dhKex{ | var dhKexStrat = map[CurveID]dhKex{ | ||||
@@ -89,8 +92,7 @@ var dhKexStrat = map[CurveID]dhKex{ | |||||
CurveP384: &kexNist{}, | CurveP384: &kexNist{}, | ||||
CurveP521: &kexNist{}, | CurveP521: &kexNist{}, | ||||
X25519: &kexX25519{}, | X25519: &kexX25519{}, | ||||
sidhP503: &kexSidhP503{}, | |||||
HybridSidhP503Curve25519: &kexHybridSidhP503X25519{}, | |||||
HybridSIDHp503Curve25519: &kexHybridSIDHp503X25519{}, | |||||
} | } | ||||
func newKeySchedule13(suite *cipherSuite, config *Config, clientRandom []byte) *keySchedule13 { | func newKeySchedule13(suite *cipherSuite, config *Config, clientRandom []byte) *keySchedule13 { | ||||
@@ -1222,17 +1224,17 @@ func (kexX25519) derive(c *Conn, ks keyShare, secretKey []byte) []byte { | |||||
} | } | ||||
// KEX: SIDH/503 | // KEX: SIDH/503 | ||||
func (kexSidhP503) generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) { | |||||
func (kexSIDHp503) generate(c *Conn, groupId CurveID) ([]byte, keyShare, error) { | |||||
var variant, _ = getSidhKeyVariant(c.isClient) | var variant, _ = getSidhKeyVariant(c.isClient) | ||||
var prvKey = sidh.NewPrivateKey(sidh.FP_503, variant) | var prvKey = sidh.NewPrivateKey(sidh.FP_503, variant) | ||||
if prvKey.Generate(c.config.rand()) != nil { | if prvKey.Generate(c.config.rand()) != nil { | ||||
return nil, keyShare{}, errors.New("tls: private SIDH key generation failed") | return nil, keyShare{}, errors.New("tls: private SIDH key generation failed") | ||||
} | } | ||||
pubKey := prvKey.GeneratePublicKey() | pubKey := prvKey.GeneratePublicKey() | ||||
return prvKey.Export(), keyShare{group: sidhP503, data: pubKey.Export()}, nil | |||||
return prvKey.Export(), keyShare{group: 0, data: pubKey.Export()}, nil | |||||
} | } | ||||
func (kexSidhP503) derive(c *Conn, ks keyShare, key []byte) []byte { | |||||
func (kexSIDHp503) derive(c *Conn, ks keyShare, key []byte) []byte { | |||||
var prvVariant, pubVariant = getSidhKeyVariant(c.isClient) | var prvVariant, pubVariant = getSidhKeyVariant(c.isClient) | ||||
var prvKeySize = P503PrvKeySz | var prvKeySize = P503PrvKeySz | ||||
@@ -1256,12 +1258,12 @@ func (kexSidhP503) derive(c *Conn, ks keyShare, key []byte) []byte { | |||||
} | } | ||||
// KEX Hybrid SIDH/503-X25519 | // 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 | |||||
func (kex *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 | // Generate ephemeral key for classic x25519 | ||||
private, ks, err = dhKexStrat[X25519].generate(c, groupId) | |||||
private, ks, err = kex.classicKEX.generate(c, groupId) | |||||
if err != nil { | if err != nil { | ||||
return | return | ||||
} | } | ||||
@@ -1269,33 +1271,33 @@ func (kexHybridSidhP503X25519) generate(c *Conn, groupId CurveID) (private []byt | |||||
copy(pubHybrid[:], ks.data) | copy(pubHybrid[:], ks.data) | ||||
// Generate PQ ephemeral key for SIDH | // Generate PQ ephemeral key for SIDH | ||||
private, ks, err = dhKexStrat[sidhP503].generate(c, groupId) | |||||
private, ks, err = kex.pqKEX.generate(c, groupId) | |||||
if err != nil { | if err != nil { | ||||
return | return | ||||
} | } | ||||
copy(prvHybrid[x25519SharedSecretSz:], private) | copy(prvHybrid[x25519SharedSecretSz:], private) | ||||
copy(pubHybrid[x25519SharedSecretSz:], ks.data) | copy(pubHybrid[x25519SharedSecretSz:], ks.data) | ||||
return prvHybrid[:], keyShare{group: HybridSidhP503Curve25519, data: pubHybrid[:]}, nil | |||||
return prvHybrid[:], keyShare{group: HybridSIDHp503Curve25519, data: pubHybrid[:]}, nil | |||||
} | } | ||||
func (kexHybridSidhP503X25519) derive(c *Conn, ks keyShare, key []byte) []byte { | |||||
var sharedKey [SidhP503Curve25519SharedKeySz]byte | |||||
func (kex *kexHybridSIDHp503X25519) derive(c *Conn, ks keyShare, key []byte) []byte { | |||||
var sharedKey [SIDHp503Curve25519SharedKeySz]byte | |||||
var ret []byte | var ret []byte | ||||
var tmpKs keyShare | var tmpKs keyShare | ||||
// Key agreement for classic | // Key agreement for classic | ||||
tmpKs.group = X25519 | tmpKs.group = X25519 | ||||
tmpKs.data = ks.data[:x25519SharedSecretSz] | tmpKs.data = ks.data[:x25519SharedSecretSz] | ||||
ret = dhKexStrat[X25519].derive(c, tmpKs, key[:x25519SharedSecretSz]) | |||||
ret = kex.classicKEX.derive(c, tmpKs, key[:x25519SharedSecretSz]) | |||||
if ret == nil { | if ret == nil { | ||||
return nil | return nil | ||||
} | } | ||||
copy(sharedKey[:], ret) | copy(sharedKey[:], ret) | ||||
// Key agreement for PQ | // Key agreement for PQ | ||||
tmpKs.group = sidhP503 | |||||
tmpKs.group = 0 | |||||
tmpKs.data = ks.data[x25519SharedSecretSz:] | tmpKs.data = ks.data[x25519SharedSecretSz:] | ||||
ret = dhKexStrat[sidhP503].derive(c, tmpKs, key[x25519SharedSecretSz:]) | |||||
ret = kex.pqKEX.derive(c, tmpKs, key[x25519SharedSecretSz:]) | |||||
if ret == nil { | if ret == nil { | ||||
return nil | return nil | ||||
} | } | ||||
@@ -24,7 +24,7 @@ bssl server \ | |||||
# ECDSA and SIDH/P503-X25519 | # ECDSA and SIDH/P503-X25519 | ||||
bssl server \ | bssl server \ | ||||
-key ecdsa.pem \ | -key ecdsa.pem \ | ||||
-curves x25519sidh503 \ | |||||
-curves X25519-SIDHp503:X25519:P-256:P-384:P-521 \ | |||||
-min-version tls1.3 -max-version tls1.3 \ | -min-version tls1.3 -max-version tls1.3 \ | ||||
-accept 7443 -loop -www \ | -accept 7443 -loop -www \ | ||||
-debug 2>&1 & | -debug 2>&1 & | ||||
@@ -20,7 +20,7 @@ RE_PATTERN_ALPN = "ALPN protocol: npn_proto$" | |||||
# Successful TLS establishement from TRIS | # Successful TLS establishement from TRIS | ||||
RE_TRIS_ALL_PASSED = ".*All handshakes passed.*" | RE_TRIS_ALL_PASSED = ".*All handshakes passed.*" | ||||
# TLS handshake from BoringSSL with SIDH/P503-X25519 | # TLS handshake from BoringSSL with SIDH/P503-X25519 | ||||
RE_BORINGSSL_P503 = "ECDHE curve: x25519sidh503" | |||||
RE_BORINGSSL_P503 = "ECDHE curve: X25519-SIDHp503" | |||||
class Docker(object): | class Docker(object): | ||||
''' Utility class used for starting/stoping servers and clients during tests''' | ''' Utility class used for starting/stoping servers and clients during tests''' | ||||
@@ -227,7 +227,7 @@ class InteropServer_BoringSSL(InteropServer, ServerNominalMixin, ServerClientAut | |||||
''' | ''' | ||||
Connects to TRIS server listening on 7443 and tries to perform key agreement with SIDH/P503-X25519 | Connects to TRIS server listening on 7443 and tries to perform key agreement with SIDH/P503-X25519 | ||||
''' | ''' | ||||
res = self.d.run_client(self.CLIENT_NAME, self.server_ip+":7443 "+'-curves x25519sidh503') | |||||
res = self.d.run_client(self.CLIENT_NAME, self.server_ip+":7443 "+'-curves X25519-SIDHp503') | |||||
self.assertEqual(res[0], 0) | self.assertEqual(res[0], 0) | ||||
self.assertIsNotNone(re.search(RE_BORINGSSL_P503, res[1], re.MULTILINE)) | self.assertIsNotNone(re.search(RE_BORINGSSL_P503, res[1], re.MULTILINE)) | ||||
self.assertIsNotNone(re.search(RE_PATTERN_HELLO_TLS_13_NORESUME, res[1], re.MULTILINE)) | self.assertIsNotNone(re.search(RE_PATTERN_HELLO_TLS_13_NORESUME, res[1], re.MULTILINE)) | ||||
@@ -257,7 +257,7 @@ class InteropClient_BoringSSL(InteropClient, ClientNominalMixin, ClientClientAut | |||||
''' | ''' | ||||
Connects to BoringSSL server listening on 7443 and tries to perform key agreement with SIDH/P503-X25519 | 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 SIDH-P503-X25519 ' + self.server_ip+":7443") | |||||
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr X25519-SIDHp503 ' + self.server_ip+":7443") | |||||
self.assertEqual(res[0], 0) | self.assertEqual(res[0], 0) | ||||
self.assertIsNotNone(re.search(RE_TRIS_ALL_PASSED, res[1], re.MULTILINE)) | self.assertIsNotNone(re.search(RE_TRIS_ALL_PASSED, res[1], re.MULTILINE)) | ||||
@@ -278,7 +278,7 @@ class InteropServer_TRIS(ClientNominalMixin, InteropServer, unittest.TestCase): | |||||
self.assertEqual(res[0], 0) | self.assertEqual(res[0], 0) | ||||
def test_SIDH(self): | def test_SIDH(self): | ||||
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr SIDH-P503-X25519 '+self.server_ip+":7443") | |||||
res = self.d.run_client(self.CLIENT_NAME, '-rsa=false -ecdsa=true -qr X25519-SIDHp503 '+self.server_ip+":7443") | |||||
self.assertEqual(res[0], 0) | self.assertEqual(res[0], 0) | ||||
def test_server_doesnt_support_SIDH(self): | def test_server_doesnt_support_SIDH(self): | ||||
@@ -56,7 +56,7 @@ func NewServer() *server { | |||||
} | } | ||||
func enableQR(s *server, enableDefault bool) { | func enableQR(s *server, enableDefault bool) { | ||||
var sidhCurves = []tls.CurveID{tls.HybridSidhP503Curve25519} | |||||
var sidhCurves = []tls.CurveID{tls.HybridSIDHp503Curve25519} | |||||
if enableDefault { | if enableDefault { | ||||
var defaultCurvePreferences = []tls.CurveID{tls.X25519, tls.CurveP256, tls.CurveP384, tls.CurveP521} | 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, defaultCurvePreferences...) | ||||
@@ -53,10 +53,8 @@ func (c *Client) setMinMaxTLS(ver uint16) { | |||||
func getQrAlgoId(qr string) tls.CurveID { | func getQrAlgoId(qr string) tls.CurveID { | ||||
switch qr { | switch qr { | ||||
case "SIDH-P503-X25519": | |||||
return tls.HybridSidhP503Curve25519 | |||||
//case "SIDH-P751-X448": | |||||
// return tls.HybridSidhP751Curve448 | |||||
case "X25519-SIDHp503": | |||||
return tls.HybridSIDHp503Curve25519 | |||||
default: | default: | ||||
return 0 | return 0 | ||||
} | } | ||||
@@ -110,7 +108,7 @@ func main() { | |||||
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.StringVar(&qrAlgoName, "qr", "", "Specifies qr algorithm from following list:\n[X25519-SIDHp503]") | |||||
flag.Parse() | flag.Parse() | ||||
if flag.NArg() != 1 { | if flag.NArg() != 1 { | ||||
flag.Usage() | flag.Usage() | ||||
@@ -123,12 +123,7 @@ const ( | |||||
X25519 CurveID = 29 | X25519 CurveID = 29 | ||||
// Experimental KEX | // Experimental KEX | ||||
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 | |||||
HybridSIDHp503Curve25519 CurveID = 0xFE30 | |||||
) | ) | ||||
// TLS 1.3 Key Share | // TLS 1.3 Key Share | ||||
@@ -658,7 +658,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) alert { | |||||
return alertDecodeError | return alertDecodeError | ||||
} | } | ||||
case extensionKeyShare: | case extensionKeyShare: | ||||
// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.5 | |||||
// https://tools.ietf.org/html/rfc8446#section-4.2.8 | |||||
if length < 2 { | if length < 2 { | ||||
return alertDecodeError | return alertDecodeError | ||||
} | } | ||||