This is an automated email from the git hooks/post-receive script.
meskio pushed a change to branch master in repository pluggable-transports/obfs4.
from cbf3f3c Bump the version to 0.0.13-dev new d5a5161 doc: Correct why the obfs4 change is backward compatible (NFC) new 83f01d5 transports/meek_lite: Remove utls support new 77af0cb build: Do the release ritual for obfs4proxy-0.0.13 new f63befd build: Bump the version to 0.0.14-dev new 586fbf4 Test that public keys are not always on the prime-order subgroup. new 5fcbb0e Do not clamp the private key before Elligator inverse map. new ef83204 doc: Add a changelog entry and clarified a comment (NFC) new 336a71d build: Do the release ritual for obfs4proxy-0.0.14
The 8 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "add" were already present in the repository and have only been added to this reference.
Summary of changes: ChangeLog | 8 +- common/ntor/ntor.go | 3 - common/ntor/ntor_test.go | 136 +++++++++++++++++++++ go.mod | 1 - go.sum | 17 --- internal/README.md | 7 +- internal/x25519ell2/x25519ell2.go | 4 + obfs4proxy/obfs4proxy.go | 2 +- transports/meeklite/base.go | 6 +- transports/meeklite/hpkp_lite.go | 124 ------------------- transports/meeklite/meek.go | 47 ++----- transports/meeklite/transport.go | 250 -------------------------------------- 12 files changed, 166 insertions(+), 439 deletions(-) delete mode 100644 transports/meeklite/hpkp_lite.go delete mode 100644 transports/meeklite/transport.go
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit d5a51619ebe50fb5cd5b5060c2e57c99826543a8 Author: Yawning Angel yawning@schwanenlied.me AuthorDate: Thu Jan 27 07:55:29 2022 +0000
doc: Correct why the obfs4 change is backward compatible (NFC) --- internal/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/internal/README.md b/internal/README.md index 05aa472..a2a6e2b 100644 --- a/internal/README.md +++ b/internal/README.md @@ -13,10 +13,9 @@ be it via the modified scalar basepoint multiply or via decoding a representative will be somewhat non-standard, but will interoperate with a standard X25519 scalar-multiply.
-As the obfs4 handshake does not include the decoded representative in -any of it's authenticated handshake digest calculations, this change is -fully-backward compatible (though the non-upgraded side of the connection -will still be trivially distinguishable from random). +As the representative to public key transform should be identical, +this change is fully-backward compatible (though the non-upgraded side +of the connection will still be trivially distinguishable from random).
##### Maintainer's rant
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit 83f01d5a74379114101e2384709d4e9ae6f6201e Author: Yawning Angel yawning@schwanenlied.me AuthorDate: Thu Feb 3 22:18:44 2022 +0000
transports/meek_lite: Remove utls support
While this was a good idea back when I did it:
* People don't like the fact that it requires a fork of utls to fix compatibility issues, and would rather spend 3 years complaining about it instead of spending a weekend to fix the issues in upstream.
* Tor over meek is trivially identifiable regardless of utls or not.
* Malware asshats ruined domain fronting for everybody. --- ChangeLog | 2 + go.mod | 1 - go.sum | 17 --- transports/meeklite/base.go | 6 +- transports/meeklite/hpkp_lite.go | 124 ------------------- transports/meeklite/meek.go | 47 ++------ transports/meeklite/transport.go | 250 --------------------------------------- 7 files changed, 17 insertions(+), 430 deletions(-)
diff --git a/ChangeLog b/ChangeLog index dc7a357..d9cc09d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ Changes in version 0.0.13 - UNRELEASED: + - Stop using utls entirely for TLS signature normalization (meek_lite). + - Stop pinning the certificate chain for default bridges (meek_lite).
Changes in version 0.0.12 - 2021-12-31: - Fix the long standing distinguishers associated with agl's Elligator2 diff --git a/go.mod b/go.mod index 622ac6f..49e491b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ require ( git.torproject.org/pluggable-transports/goptlib.git v1.0.0 github.com/dchest/siphash v1.2.1 gitlab.com/yawning/edwards25519-extra.git v0.0.0-20211229043746-2f91fcc9fbdb - gitlab.com/yawning/utls.git v0.0.12-1 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 ) diff --git a/go.sum b/go.sum index 5de7fd9..b542a6b 100644 --- a/go.sum +++ b/go.sum @@ -4,32 +4,15 @@ git.torproject.org/pluggable-transports/goptlib.git v1.0.0 h1:ElTwFFPKf/tA6x5nuI git.torproject.org/pluggable-transports/goptlib.git v1.0.0/go.mod h1:YT4XMSkuEXbtqlydr9+OxqFAyspUv0Gr9qhM3B++o/Q= github.com/dchest/siphash v1.2.1 h1:4cLinnzVJDKxTCl9B01807Yiy+W7ZzVHj/KIroQRvT4= github.com/dchest/siphash v1.2.1/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBlVnOnt4= -github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= -github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= -github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= -gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= -gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= gitlab.com/yawning/edwards25519-extra.git v0.0.0-20211229043746-2f91fcc9fbdb h1:qRSZHsODmAP5qDvb3YsO7Qnf3TRiVbGxNG/WYnlM4/o= gitlab.com/yawning/edwards25519-extra.git v0.0.0-20211229043746-2f91fcc9fbdb/go.mod h1:gvdJuZuO/tPZyhEV8K3Hmoxv/DWud5L4qEQxfYjEUTo= -gitlab.com/yawning/utls.git v0.0.12-1 h1:RL6O0MP2YI0KghuEU/uGN6+8b4183eqNWoYgx7CXD0U= -gitlab.com/yawning/utls.git v0.0.12-1/go.mod h1:3ONKiSFR9Im/c3t5RKmMJTVdmZN496FNyk3mjrY1dyo= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/transports/meeklite/base.go b/transports/meeklite/base.go index 399ff4c..e9d8ca1 100644 --- a/transports/meeklite/base.go +++ b/transports/meeklite/base.go @@ -85,5 +85,7 @@ func (cf *meekClientFactory) Dial(network, addr string, dialFn base.DialFunc, ar return newMeekConn(network, addr, dialFn, ca) }
-var _ base.ClientFactory = (*meekClientFactory)(nil) -var _ base.Transport = (*Transport)(nil) +var ( + _ base.ClientFactory = (*meekClientFactory)(nil) + _ base.Transport = (*Transport)(nil) +) diff --git a/transports/meeklite/hpkp_lite.go b/transports/meeklite/hpkp_lite.go deleted file mode 100644 index 97ac590..0000000 --- a/transports/meeklite/hpkp_lite.go +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2019 Yawning Angel <yawning at schwanenlied dot me> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see https://www.gnu.org/licenses/. - */ - -package meeklite - -import ( - "crypto/sha256" - "crypto/x509" - "encoding/base64" - "time" - - "golang.org/x/net/idna" -) - -var builtinPinDB *hpkpDatabase - -type hpkpDatabase struct { - pins map[string]*pinEntry -} - -type pinEntry struct { - digests map[string]bool - expiry time.Time -} - -func (db *hpkpDatabase) HasPins(host string) (string, bool) { - h, err := normalizeHost(host) - if err == nil { - if entry := db.pins[host]; entry != nil { - if time.Now().Before(entry.expiry) { - return h, true - } - } - } - return h, false -} - -func (db *hpkpDatabase) Validate(host string, chains [][]*x509.Certificate) bool { - host, err := normalizeHost(host) - if err != nil { - return false - } - entry := db.pins[host] - if entry == nil { - return false - } - if time.Now().After(entry.expiry) { - // If the pins are expired, assume that it is valid. - return true - } - - // Search for an intersection between the pins and the cert chain. - for _, chain := range chains { - for _, cert := range chain { - derivedPin := sha256.Sum256(cert.RawSubjectPublicKeyInfo) - derivedPinEncoded := base64.StdEncoding.EncodeToString(derivedPin[:]) - if entry.digests[derivedPinEncoded] { - return true - } - } - } - - return false -} - -func (db *hpkpDatabase) Add(host string, pins []string, expiry time.Time) { - h, err := normalizeHost(host) - if err != nil { - panic("failed to add hpkp pin, invalid host: " + err.Error()) - } - - pinMap := make(map[string]bool) - for _, pin := range pins { - pinMap[pin] = true - } - - db.pins[h] = &pinEntry{ - digests: pinMap, - expiry: expiry, - } -} - -func normalizeHost(host string) (string, error) { - return idna.Lookup.ToASCII(host) -} - -func init() { - builtinPinDB = &hpkpDatabase{ - pins: make(map[string]*pinEntry), - } - - // Pin all of Microsoft Azure's root CA certificates for the Tor Browser - // Azure bridge. - // - // See: https://docs.microsoft.com/en-us/azure/security/fundamentals/tls-certificate... - builtinPinDB.Add( - "ajax.aspnetcdn.com", - []string{ - "i7WTqTvh0OioIruIfFR4kMPnBqrS2rdiVPl/s2uC/CY=", // DigiCert Global Root G2 - 2038-01-15 12:00:00 - "r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=", // DigiCert Global Root CA - 2031-11-10 00:00:00 - "Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o=", // Baltimore CyberTrust Root - 2025-05-12 23:59:00 - "7KDxgUAs56hlKzG00DbfJH46MLf0GlDZHsT5CwBrQ6E=", // D-TRUST Root Class 3 CA 2 2009 - 2029-11-05 08:35:58 - "svcpi1K/LDysTd/nLeTWgqxYlXWVmC8rYjAa9ZfGmcU=", // Microsoft RSA Root Certificate Authority 2017 - 2042-07-18 23:00:23 - "NfU84SZGEeAzQP434ex9TMmGxWE9ynD9BKpEVF8tryg=", // Microsoft ECC Root Certificate Authority 2017 - 2042-07-18 23:16:04 - }, - // As of 2020-12-07, we're getting the "DigiCert Global Root CA" - // certificate, so our expiration time matches this certificate. - time.Date(2031, time.November, 20, 00, 00, 00, 00, time.UTC), - ) -} diff --git a/transports/meeklite/meek.go b/transports/meeklite/meek.go index 367563b..17c7a67 100644 --- a/transports/meeklite/meek.go +++ b/transports/meeklite/meek.go @@ -41,20 +41,16 @@ import ( gourl "net/url" "os" "runtime" - "strings" "sync" "time"
"git.torproject.org/pluggable-transports/goptlib.git" "gitlab.com/yawning/obfs4.git/transports/base" - utls "gitlab.com/yawning/utls.git" )
const ( - urlArg = "url" - frontArg = "front" - utlsArg = "utls" - disableHPKPArg = "disableHPKP" + urlArg = "url" + frontArg = "front"
maxChanBacklog = 16
@@ -77,9 +73,6 @@ var ( type meekClientArgs struct { url *gourl.URL front string - - utls *utls.ClientHelloID - disableHPKP bool }
func (ca *meekClientArgs) Network() string { @@ -111,25 +104,13 @@ func newClientArgs(args *pt.Args) (ca *meekClientArgs, err error) { // Parse the (optional) front argument. ca.front, _ = args.Get(frontArg)
- // Parse the (optional) utls argument. - utlsOpt, _ := args.Get(utlsArg) - if ca.utls, err = parseClientHelloID(utlsOpt); err != nil { - return nil, err - } - - // Parse the (optional) HPKP disable argument. - hpkpOpt, _ := args.Get(disableHPKPArg) - if strings.ToLower(hpkpOpt) == "true" { - ca.disableHPKP = true - } - return ca, nil }
type meekConn struct { - args *meekClientArgs - sessionID string - roundTripper http.RoundTripper + args *meekClientArgs + sessionID string + transport *http.Transport
closeOnce sync.Once workerWrChan chan []byte @@ -261,7 +242,7 @@ func (c *meekConn) roundTrip(sndBuf []byte) (recvBuf []byte, err error) { req.Header.Set("X-Session-Id", c.sessionID) req.Header.Set("User-Agent", "")
- resp, err = c.roundTripper.RoundTrip(req) + resp, err = c.transport.RoundTrip(req) if err != nil { return nil, err } @@ -362,18 +343,10 @@ func newMeekConn(network, addr string, dialFn base.DialFunc, ca *meekClientArgs) return nil, err }
- var rt http.RoundTripper - switch ca.utls { - case nil: - rt = &http.Transport{Dial: dialFn} - default: - rt = newRoundTripper(dialFn, ca.utls, ca.disableHPKP) - } - conn := &meekConn{ args: ca, sessionID: id, - roundTripper: rt, + transport: &http.Transport{Dial: dialFn}, workerWrChan: make(chan []byte, maxChanBacklog), workerRdChan: make(chan []byte, maxChanBacklog), workerCloseChan: make(chan struct{}), @@ -394,5 +367,7 @@ func newSessionID() (string, error) { return hex.EncodeToString(h[:16]), nil }
-var _ net.Conn = (*meekConn)(nil) -var _ net.Addr = (*meekClientArgs)(nil) +var ( + _ net.Conn = (*meekConn)(nil) + _ net.Addr = (*meekClientArgs)(nil) +) diff --git a/transports/meeklite/transport.go b/transports/meeklite/transport.go deleted file mode 100644 index 8ff02a5..0000000 --- a/transports/meeklite/transport.go +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2019 Yawning Angel <yawning at schwanenlied dot me> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see https://www.gnu.org/licenses/. - */ - -package meeklite - -import ( - "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "net" - "net/http" - "net/url" - "strconv" - "strings" - "sync" - - "gitlab.com/yawning/obfs4.git/common/log" - "gitlab.com/yawning/obfs4.git/transports/base" - utls "gitlab.com/yawning/utls.git" - "golang.org/x/net/http2" -) - -var ( - errProtocolNegotiated = errors.New("meek_lite: protocol negotiated") - - // This should be kept in sync with what is available in utls. - clientHelloIDMap = map[string]*utls.ClientHelloID{ - "hellogolang": nil, // Don't bother with utls. - "hellorandomized": &utls.HelloRandomized, - "hellorandomizedalpn": &utls.HelloRandomizedALPN, - "hellorandomizednoalpn": &utls.HelloRandomizedNoALPN, - "hellofirefox_auto": &utls.HelloFirefox_Auto, - "hellofirefox_55": &utls.HelloFirefox_55, - "hellofirefox_56": &utls.HelloFirefox_56, - "hellofirefox_63": &utls.HelloFirefox_63, - "hellofirefix_65": &utls.HelloFirefox_65, - "hellochrome_auto": &utls.HelloChrome_Auto, - "hellochrome_58": &utls.HelloChrome_58, - "hellochrome_62": &utls.HelloChrome_62, - "hellochrome_70": &utls.HelloChrome_70, - "hellochrome_72": &utls.HelloChrome_72, - "hellochrome_83": &utls.HelloChrome_83, - "helloios_auto": &utls.HelloIOS_Auto, - "helloios_11_1": &utls.HelloIOS_11_1, - "helloios_12_1": &utls.HelloIOS_12_1, - } - defaultClientHello = &utls.HelloFirefox_Auto -) - -type roundTripper struct { - sync.Mutex - - clientHelloID *utls.ClientHelloID - dialFn base.DialFunc - transport http.RoundTripper - - initConn net.Conn - disableHPKP bool -} - -func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - // Note: This isn't protected with a lock, since the meeklite ioWorker - // serializes RoundTripper requests. - // - // This also assumes that req.URL.Host will remain constant for the - // lifetime of the roundTripper, which is a valid assumption for meeklite. - if rt.transport == nil { - if err := rt.getTransport(req); err != nil { - return nil, err - } - } - return rt.transport.RoundTrip(req) -} - -func (rt *roundTripper) getTransport(req *http.Request) error { - switch strings.ToLower(req.URL.Scheme) { - case "http": - rt.transport = newHTTPTransport(rt.dialFn, nil) - return nil - case "https": - default: - return fmt.Errorf("meek_lite: invalid URL scheme: '%v'", req.URL.Scheme) - } - - _, err := rt.dialTLS("tcp", getDialTLSAddr(req.URL)) - switch err { - case errProtocolNegotiated: - case nil: - // Should never happen. - panic("meek_lite: dialTLS returned no error when determining transport") - default: - return err - } - - return nil -} - -func (rt *roundTripper) dialTLS(network, addr string) (net.Conn, error) { - // Unlike rt.transport, this is protected by a critical section - // since past the initial manual call from getTransport, the HTTP - // client will be the caller. - rt.Lock() - defer rt.Unlock() - - // If we have the connection from when we determined the HTTPS - // transport to use, return that. - if conn := rt.initConn; conn != nil { - rt.initConn = nil - return conn, nil - } - - rawConn, err := rt.dialFn(network, addr) - if err != nil { - return nil, err - } - - var host string - if host, _, err = net.SplitHostPort(addr); err != nil { - host = addr - } - - var verifyPeerCertificateFn func([][]byte, [][]*x509.Certificate) error - if !rt.disableHPKP { - if pinHost, ok := builtinPinDB.HasPins(host); ok { - if rt.transport == nil { - log.Debugf("meek_lite - HPKP enabled for host: %v", pinHost) - } - verifyPeerCertificateFn = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { - if !builtinPinDB.Validate(pinHost, verifiedChains) { - log.Errorf("meek_lite - HPKP validation failure, potential MITM for host: %v", pinHost) - return fmt.Errorf("meek_lite: HPKP validation failure for host: %v", pinHost) - } - return nil - } - } - } else if rt.transport == nil { - log.Warnf("meek_lite - HPKP disabled for host: %v", host) - } - - conn := utls.UClient(rawConn, &utls.Config{ - ServerName: host, - VerifyPeerCertificate: verifyPeerCertificateFn, - - // `crypto/tls` gradually ramps up the record size. While this is - // a good optimization and is a relatively common server feature, - // neither Firefox nor Chromium appear to use such optimizations. - DynamicRecordSizingDisabled: true, - }, *rt.clientHelloID) - if err = conn.Handshake(); err != nil { - conn.Close() - return nil, err - } - - if rt.transport != nil { - return conn, nil - } - - // No http.Transport constructed yet, create one based on the results - // of ALPN. - switch conn.ConnectionState().NegotiatedProtocol { - case http2.NextProtoTLS: - // The remote peer is speaking HTTP 2 + TLS. - rt.transport = &http2.Transport{DialTLS: rt.dialTLSHTTP2} - default: - // Assume the remote peer is speaking HTTP 1.x + TLS. - rt.transport = newHTTPTransport(nil, rt.dialTLS) - } - - // Stash the connection just established for use servicing the - // actual request (should be near-immediate). - rt.initConn = conn - - return nil, errProtocolNegotiated -} - -func (rt *roundTripper) dialTLSHTTP2(network, addr string, cfg *tls.Config) (net.Conn, error) { - return rt.dialTLS(network, addr) -} - -func getDialTLSAddr(u *url.URL) string { - host, port, err := net.SplitHostPort(u.Host) - if err == nil { - return net.JoinHostPort(host, port) - } - pInt, _ := net.LookupPort("tcp", u.Scheme) - - return net.JoinHostPort(u.Host, strconv.Itoa(pInt)) -} - -func newRoundTripper(dialFn base.DialFunc, clientHelloID *utls.ClientHelloID, disableHPKP bool) http.RoundTripper { - return &roundTripper{ - clientHelloID: clientHelloID, - dialFn: dialFn, - disableHPKP: disableHPKP, - } -} - -func parseClientHelloID(s string) (*utls.ClientHelloID, error) { - s = strings.ToLower(s) - switch s { - case "none": - return nil, nil - case "": - return defaultClientHello, nil - default: - if ret := clientHelloIDMap[s]; ret != nil { - return ret, nil - } - } - return nil, fmt.Errorf("invalid ClientHelloID: '%v'", s) -} - -func newHTTPTransport(dialFn, dialTLSFn base.DialFunc) *http.Transport { - base := (http.DefaultTransport).(*http.Transport) - - return &http.Transport{ - Dial: dialFn, - DialTLS: dialTLSFn, - - // Use default configuration values, taken from the runtime. - MaxIdleConns: base.MaxIdleConns, - IdleConnTimeout: base.IdleConnTimeout, - TLSHandshakeTimeout: base.TLSHandshakeTimeout, - ExpectContinueTimeout: base.ExpectContinueTimeout, - } -} - -func init() { - // Attempt to increase compatibility and performance, there's an - // encrypted link underneath, and this doesn't (shouldn't) affect - // the external fingerprint. - utls.EnableWeakCiphers() - utls.EnableVartimeGroups() - utls.EnableVartimeAES() -}
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit 77af0cba934d73c4baeb709560bcfc9a9fbc661c Author: Yawning Angel yawning@schwanenlied.me AuthorDate: Fri Feb 4 00:36:09 2022 +0000
build: Do the release ritual for obfs4proxy-0.0.13 --- ChangeLog | 2 +- obfs4proxy/obfs4proxy.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog index d9cc09d..709ebef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Changes in version 0.0.13 - UNRELEASED: +Changes in version 0.0.13 - 2022-02-04: - Stop using utls entirely for TLS signature normalization (meek_lite). - Stop pinning the certificate chain for default bridges (meek_lite).
diff --git a/obfs4proxy/obfs4proxy.go b/obfs4proxy/obfs4proxy.go index 628f56b..d92f5f5 100644 --- a/obfs4proxy/obfs4proxy.go +++ b/obfs4proxy/obfs4proxy.go @@ -50,7 +50,7 @@ import ( )
const ( - obfs4proxyVersion = "0.0.13-dev" + obfs4proxyVersion = "0.0.13" obfs4proxyLogFile = "obfs4proxy.log" socksAddr = "127.0.0.1:0" )
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit f63befd10738b9e8cfbb8875773a0627aa81ddd2 Author: Yawning Angel yawning@schwanenlied.me AuthorDate: Sun Sep 4 06:35:48 2022 +0000
build: Bump the version to 0.0.14-dev --- ChangeLog | 2 ++ obfs4proxy/obfs4proxy.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog index 709ebef..bff90ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +Changes in version 0.0.14 - UNRELEASED: + Changes in version 0.0.13 - 2022-02-04: - Stop using utls entirely for TLS signature normalization (meek_lite). - Stop pinning the certificate chain for default bridges (meek_lite). diff --git a/obfs4proxy/obfs4proxy.go b/obfs4proxy/obfs4proxy.go index d92f5f5..a2bba71 100644 --- a/obfs4proxy/obfs4proxy.go +++ b/obfs4proxy/obfs4proxy.go @@ -50,7 +50,7 @@ import ( )
const ( - obfs4proxyVersion = "0.0.13" + obfs4proxyVersion = "0.0.14-dev" obfs4proxyLogFile = "obfs4proxy.log" socksAddr = "127.0.0.1:0" )
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit 586fbf43752592ee299233274e3e5d5597bf7f34 Author: David Fifield david@bamsoftware.com AuthorDate: Fri Sep 2 11:53:57 2022 -0400
Test that public keys are not always on the prime-order subgroup.
See discussion under "Step 2" at https://elligator.org/key-exchange. --- common/ntor/ntor_test.go | 136 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+)
diff --git a/common/ntor/ntor_test.go b/common/ntor/ntor_test.go index e4d1543..7b2026d 100644 --- a/common/ntor/ntor_test.go +++ b/common/ntor/ntor_test.go @@ -30,6 +30,10 @@ package ntor import ( "bytes" "testing" + + "filippo.io/edwards25519" + "filippo.io/edwards25519/field" + "gitlab.com/yawning/edwards25519-extra.git/elligator2" )
// TestNewKeypair tests Curve25519/Elligator keypair generation. @@ -126,6 +130,138 @@ func TestHandshake(t *testing.T) { } }
+// TestPublicKeySubgroup tests that Elligator representatives produced by +// NewKeypair map to public keys that are not always on the prime-order subgroup +// of Curve25519. (And incidentally that Elligator representatives agree with +// the public key stored in the Keypair.) +// +// See discussion under "Step 2" at https://elligator.org/key-exchange. +func TestPublicKeySubgroup(t *testing.T) { + // We will test the public keys that comes out of NewKeypair by + // multiplying each one by L, the order of the prime-order subgroup of + // Curve25519, then checking the order of the resulting point. The error + // condition we are checking for specifically is output points always + // having order 1, which means that public keys are always on the + // prime-order subgroup of Curve25519, which would make Elligator + // representatives distinguishable from random. More generally, we want + // to ensure that all possible output points of low order are covered. + // + // We have to do some contortions to conform to the interfaces we use. + // We do scalar multiplication by L using Edwards coordinates, rather + // than the Montgomery coordinates output by Keypair.Public and + // Representative.ToPublic, because the Montgomery-based + // crypto/curve25519.X25519 clamps the scalar to be a multiple of 8, + // which would not allow us to use the scalar we need. The Edwards-based + // ScalarMult only accepts scalars that are strictly less than L; we + // work around this by multiplying the point by L - 1, then adding the + // point once to the product. + + scalarOrderMinus1, err := edwards25519.NewScalar().SetCanonicalBytes( + // This is the same as scMinusOne in filippo.io/edwards25519. + // https://github.com/FiloSottile/edwards25519/blob/v1.0.0/scalar.go#L34 + []byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}, + ) + if err != nil { + panic(err) + } + // Returns a new edwards25519.Point that is v multiplied by the subgroup + // order. + scalarMultOrder := func(v *edwards25519.Point) *edwards25519.Point { + p := new(edwards25519.Point) + // v * (L - 1) + v => v * L + p.ScalarMult(scalarOrderMinus1, v) + p.Add(p, v) + return p + } + + // Generates a new Keypair using NewKeypair, and returns the Keypair + // along, with its public key as a newly allocated edwards25519.Point. + generate := func() (*Keypair, *edwards25519.Point) { + kp, err := NewKeypair(true) + if err != nil { + panic(err) + } + + // We will be using the Edwards representation of the public key + // (mapped from the Elligator representative) for further + // processing. But while we're here, check that the Montgomery + // representation output by Representative agrees with the + // stored public key. + if *kp.Representative().ToPublic() != *kp.Public() { + t.Fatal(kp.Representative().ToPublic(), kp.Public()) + } + + // Do the Elligator map in Edwards coordinates. + var clamped [32]byte + copy(clamped[:], kp.Representative().Bytes()[:]) + clamped[31] &= 63 + repr, err := new(field.Element).SetBytes(clamped[:]) + if err != nil { + panic(err) + } + ed := elligator2.EdwardsFlavor(repr) + if !bytes.Equal(ed.BytesMontgomery(), kp.Public().Bytes()[:]) { + panic("Failed to derive an equivalent public key in Edwards coordinates") + } + return kp, ed + } + + // These are all the points of low order that may result from + // multiplying an Elligator-mapped point by L. We will test that all of + // them are covered. + lowOrderPoints := [][32]byte{ + /* order 1 */ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* order 2 */ {236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127}, + /* order 4 */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* order 4 */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128}, + /* order 8 */ {38, 232, 149, 143, 194, 178, 39, 176, 69, 195, 244, 137, 242, 239, 152, 240, 213, 223, 172, 5, 211, 198, 51, 57, 177, 56, 2, 136, 109, 83, 252, 5}, + /* order 8 */ {38, 232, 149, 143, 194, 178, 39, 176, 69, 195, 244, 137, 242, 239, 152, 240, 213, 223, 172, 5, 211, 198, 51, 57, 177, 56, 2, 136, 109, 83, 252, 133}, + /* order 8 */ {199, 23, 106, 112, 61, 77, 216, 79, 186, 60, 11, 118, 13, 16, 103, 15, 42, 32, 83, 250, 44, 57, 204, 198, 78, 199, 253, 119, 146, 172, 3, 122}, + /* order 8 */ {199, 23, 106, 112, 61, 77, 216, 79, 186, 60, 11, 118, 13, 16, 103, 15, 42, 32, 83, 250, 44, 57, 204, 198, 78, 199, 253, 119, 146, 172, 3, 250}, + } + counts := make(map[[32]byte]int) + for _, b := range lowOrderPoints { + counts[b] = 0 + } + // Assuming a uniform distribution of representatives, the probability + // that a specific low-order point will not be covered after n trials is + // (7/8)^n. The probability that *any* of the 8 low-order points will + // remain uncovered after n trials is at most 8 times that, 8*(7/8)^n. + // We must do at least log((1e-12)/8)/log(7/8) = 222.50 trials, in the + // worst case, to ensure a false error rate of less than 1 in a + // trillion. In practice, we keep track of the number of covered points + // and break the loop when it reaches 8, so when representatives are + // actually uniform we will usually run much fewer iterations. + numCovered := 0 + for i := 0; i < 225; i++ { + kp, pk := generate() + v := scalarMultOrder(pk) + var b [32]byte + copy(b[:], v.Bytes()) + if _, ok := counts[b]; !ok { + t.Fatalf("map(%x)*order yielded unexpected point %v", + *kp.Representative().Bytes(), b) + } + counts[b]++ + if counts[b] == 1 { + // We just covered a new point for the first time. + numCovered++ + if numCovered == len(lowOrderPoints) { + break + } + } + } + for _, b := range lowOrderPoints { + count, ok := counts[b] + if !ok { + panic(b) + } + if count == 0 { + t.Errorf("low-order point %x not covered", b) + } + } +} + // Benchmark Client/Server handshake. The actual time taken that will be // observed on either the Client or Server is half the reported time per // operation since the benchmark does both sides.
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit 5fcbb0e14064d41e4fa43013e1f0ede4028f25c5 Author: David Fifield david@bamsoftware.com AuthorDate: Fri Sep 2 11:58:48 2022 -0400
Do not clamp the private key before Elligator inverse map.
The Elligator inverse map uses the least significant bits of the private key, which clamping sets to 0, to choose a random low-order point to add to the public key, to ensure uniformity of representatives.
The other ways that the private key is used, namely in calls to curve25519.ScalarMult and curve25519.ScalarBaseMult, do their own clamping when necessary and are documented to accept a uniformly random scalar. --- common/ntor/ntor.go | 3 --- 1 file changed, 3 deletions(-)
diff --git a/common/ntor/ntor.go b/common/ntor/ntor.go index af24b68..17a9ff7 100644 --- a/common/ntor/ntor.go +++ b/common/ntor/ntor.go @@ -273,9 +273,6 @@ func NewKeypair(elligator bool) (*Keypair, error) { return nil, err } digest := sha512.Sum512(priv) - digest[0] &= 248 - digest[31] &= 127 - digest[31] |= 64 copy(priv, digest[:])
if elligator {
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit ef832041b71366f5e377297d2b4ff134077cfab4 Author: Yawning Angel yawning@schwanenlied.me AuthorDate: Sun Sep 4 06:38:30 2022 +0000
doc: Add a changelog entry and clarified a comment (NFC) --- ChangeLog | 2 ++ internal/x25519ell2/x25519ell2.go | 4 ++++ 2 files changed, 6 insertions(+)
diff --git a/ChangeLog b/ChangeLog index bff90ed..9223921 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ Changes in version 0.0.14 - UNRELEASED: + - Fixed the incompete previous fix to the Elligator 2 subgroup issue (Thanks + to David Fifield).
Changes in version 0.0.13 - 2022-02-04: - Stop using utls entirely for TLS signature normalization (meek_lite). diff --git a/internal/x25519ell2/x25519ell2.go b/internal/x25519ell2/x25519ell2.go index c3676ed..eb2b1dd 100644 --- a/internal/x25519ell2/x25519ell2.go +++ b/internal/x25519ell2/x25519ell2.go @@ -144,6 +144,10 @@ func uToRepresentative(representative *[32]byte, u *field.Element, tweak byte) b // Note that this function will fail and return false for about // half of private keys. // +// The `privateKey` input MUST be the full 32-bytes of entropy +// (X25519-style "clamping" will result in non-uniformly distributed +// representatives). +// // WARNING: The underlying scalar multiply explicitly does not clear // the cofactor, and thus the public keys will be different from // those produced by normal implementations.
This is an automated email from the git hooks/post-receive script.
meskio pushed a commit to branch master in repository pluggable-transports/obfs4.
commit 336a71d6e4cfd2d33e9c57797828007ad74975e9 Author: Yawning Angel yawning@schwanenlied.me AuthorDate: Sun Sep 4 06:40:09 2022 +0000
build: Do the release ritual for obfs4proxy-0.0.14 --- ChangeLog | 2 +- obfs4proxy/obfs4proxy.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog index 9223921..824d006 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Changes in version 0.0.14 - UNRELEASED: +Changes in version 0.0.14 - 2022-09-04: - Fixed the incompete previous fix to the Elligator 2 subgroup issue (Thanks to David Fifield).
diff --git a/obfs4proxy/obfs4proxy.go b/obfs4proxy/obfs4proxy.go index a2bba71..f295926 100644 --- a/obfs4proxy/obfs4proxy.go +++ b/obfs4proxy/obfs4proxy.go @@ -50,7 +50,7 @@ import ( )
const ( - obfs4proxyVersion = "0.0.14-dev" + obfs4proxyVersion = "0.0.14" obfs4proxyLogFile = "obfs4proxy.log" socksAddr = "127.0.0.1:0" )
tor-commits@lists.torproject.org