From c89ecce3e0a3dfba243d42849599ab07b8679fc1 Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Fri, 2 Apr 2021 17:36:06 +0200 Subject: [PATCH] feat: support embedding encrypted psiphon config (#285) We use an optional build tag to hide this configuration. When you choose this configuration, you need to provide the encrypted config as well as the corresponding decryption key. This is not the final design. This is an interim design to start working and experimenting with this functionality. The general idea here is to support psiphon in the binaries we build without committing the psiphon config to the repository itself. Part of https://github.com/ooni/probe/issues/985 --- go.mod | 1 + go.sum | 4 +++ internal/engine/.gitignore | 2 ++ internal/engine/session.go | 9 ------- internal/engine/session_nopsiphon.go | 14 ++++++++++ internal/engine/session_psiphon.go | 34 +++++++++++++++++++++++++ internal/engine/session_psiphon_test.go | 19 ++++++++++++++ 7 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 internal/engine/session_nopsiphon.go create mode 100644 internal/engine/session_psiphon.go create mode 100644 internal/engine/session_psiphon_test.go diff --git a/go.mod b/go.mod index 77327f2..5716fb9 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/ooni/probe-cli/v3 go 1.16 require ( + filippo.io/age v1.0.0-rc.1 git.torproject.org/pluggable-transports/goptlib.git v1.1.0 github.com/alecthomas/kingpin v2.2.6+incompatible github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect diff --git a/go.sum b/go.sum index 1fe72ff..187b8a6 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +filippo.io/age v1.0.0-rc.1 h1:jQ+dz16Xxx3W/WY+YS0J96nVAAidLHO3kfQe0eOmKgI= +filippo.io/age v1.0.0-rc.1/go.mod h1:Vvd9IlwNo4Au31iqNZeZVnYtGcOf/wT4mtvZQ2ODlSk= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.schwanenlied.me/yawning/bsaes.git v0.0.0-20190320102049-26d1add596b6 h1:zOrl5/RvK48MxMrif6Z+/OpuYyRnvB+ZTrQWEV9VYb0= git.schwanenlied.me/yawning/bsaes.git v0.0.0-20190320102049-26d1add596b6/go.mod h1:BWqTsj8PgcPriQJGl7el20J/7TuT1d/hSyFDXMEpoEo= @@ -518,6 +520,7 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -605,6 +608,7 @@ golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= 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= diff --git a/internal/engine/.gitignore b/internal/engine/.gitignore index 4969276..266f6d7 100644 --- a/internal/engine/.gitignore +++ b/internal/engine/.gitignore @@ -12,4 +12,6 @@ /oohelper /oohelperd /oonipsiphon/ +/psiphon-config.json.age +/psiphon-config.key .DS_Store diff --git a/internal/engine/session.go b/internal/engine/session.go index 30371aa..d1030ad 100644 --- a/internal/engine/session.go +++ b/internal/engine/session.go @@ -275,15 +275,6 @@ func (s *Session) DefaultHTTPClient() *http.Client { return &http.Client{Transport: s.httpDefaultTransport} } -// FetchPsiphonConfig fetches psiphon config from the API. -func (s *Session) FetchPsiphonConfig(ctx context.Context) ([]byte, error) { - clnt, err := s.NewOrchestraClient(ctx) - if err != nil { - return nil, err - } - return clnt.FetchPsiphonConfig(ctx) -} - // FetchTorTargets fetches tor targets from the API. func (s *Session) FetchTorTargets( ctx context.Context, cc string) (map[string]model.TorTarget, error) { diff --git a/internal/engine/session_nopsiphon.go b/internal/engine/session_nopsiphon.go new file mode 100644 index 0000000..41a18e7 --- /dev/null +++ b/internal/engine/session_nopsiphon.go @@ -0,0 +1,14 @@ +// +build !ooni_psiphon_config + +package engine + +import "context" + +// FetchPsiphonConfig fetches psiphon config from the API. +func (s *Session) FetchPsiphonConfig(ctx context.Context) ([]byte, error) { + clnt, err := s.NewOrchestraClient(ctx) + if err != nil { + return nil, err + } + return clnt.FetchPsiphonConfig(ctx) +} diff --git a/internal/engine/session_psiphon.go b/internal/engine/session_psiphon.go new file mode 100644 index 0000000..733726a --- /dev/null +++ b/internal/engine/session_psiphon.go @@ -0,0 +1,34 @@ +// +build ooni_psiphon_config + +package engine + +import ( + "bytes" + "context" + _ "embed" + "io/ioutil" + + "filippo.io/age" +) + +//go:embed psiphon-config.json.age +var psiphonConfigJSONAge []byte + +//go:embed psiphon-config.key +var psiphonConfigSecretKey string + +// FetchPsiphonConfig decrypts psiphonConfigJSONAge using +// filippo.io/age _and_ psiphonConfigSecretKey. +func (s *Session) FetchPsiphonConfig(ctx context.Context) ([]byte, error) { + key := "AGE-SECRET-KEY-1" + psiphonConfigSecretKey + identity, err := age.ParseX25519Identity(key) + if err != nil { + return nil, err + } + input := bytes.NewReader(psiphonConfigJSONAge) + output, err := age.Decrypt(input, identity) + if err != nil { + return nil, err + } + return ioutil.ReadAll(output) +} diff --git a/internal/engine/session_psiphon_test.go b/internal/engine/session_psiphon_test.go new file mode 100644 index 0000000..92c1bc1 --- /dev/null +++ b/internal/engine/session_psiphon_test.go @@ -0,0 +1,19 @@ +// +build ooni_psiphon_config + +package engine + +import ( + "context" + "testing" +) + +func TestSessionEmbeddedPsiphonConfig(t *testing.T) { + s := &Session{} + data, err := s.FetchPsiphonConfig(context.Background()) + if err != nil { + t.Fatal(err) + } + if data == nil { + t.Fatal("expected non-nil data here") + } +}