From 6d1f996d76b91372e0c66fc51c6aa03b7773a457 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 20 Oct 2022 09:24:04 -0500 Subject: [PATCH 01/55] PoC for TAP support. This fixes https://github.com/brave/nitriding/issues/26. --- enclave.go | 5 + go.mod | 24 +- go.sum | 773 +++++++++++++++++++++++++++++++++++++++++++++++++++++ proxy.go | 212 +++++++++++++++ 4 files changed, 1008 insertions(+), 6 deletions(-) create mode 100644 proxy.go diff --git a/enclave.go b/enclave.go index e26e996..f60da29 100644 --- a/enclave.go +++ b/enclave.go @@ -164,6 +164,11 @@ func (e *Enclave) Start() error { elog.Printf("Failed to set new file descriptor limit: %s", err) } + // Set up proxy that facilitates communication with the host. + if err = setupProxy(e.cfg); err != nil { + elog.Fatal(err) + } + // Get an HTTPS certificate. if e.cfg.UseACME { err = e.setupAcme() diff --git a/go.mod b/go.mod index abd8eac..b4f8fd1 100644 --- a/go.mod +++ b/go.mod @@ -4,21 +4,33 @@ go 1.19 require ( github.com/brave/viproxy v0.1.2 + github.com/containers/gvisor-tap-vsock v0.4.0 github.com/go-chi/chi/v5 v5.0.7 + github.com/google/gopacket v1.1.19 github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703 - github.com/hf/nsm v0.0.0-20211106132757-1ae65a6a69ae + github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9 github.com/mdlayher/vsock v1.1.1 github.com/milosgajdos/tenus v0.0.3 - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 - golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 + github.com/pkg/errors v0.9.1 + github.com/sirupsen/logrus v1.9.0 + github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 + github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 + github.com/vishvananda/netlink v1.2.1-beta.2 + golang.org/x/crypto v0.1.0 + golang.org/x/sys v0.1.0 + gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf ) require ( github.com/docker/libcontainer v2.2.1+incompatible // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 // indirect github.com/mdlayher/socket v0.2.3 // indirect + github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/net v0.0.0-20220811182439-13a9a731de15 // indirect - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect + golang.org/x/time v0.1.0 // indirect ) diff --git a/go.sum b/go.sum index da53495..fe2e6cc 100644 --- a/go.sum +++ b/go.sum @@ -1,62 +1,835 @@ +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/bazelbuild/rules_go v0.27.0/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/brave/viproxy v0.1.2 h1:sOY8bI1CqLNq+KyRJrEzQuWia81UmLjK5kqTqD284hs= github.com/brave/viproxy v0.1.2/go.mod h1:E5v9Ajo1sPVAmgDjKDU8fLmkoJeHjtcXJIkEm8XubpQ= +github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.2.1/go.mod h1:wCYX+dRqZdImhGucXOqTQn05AhX6EUDaGEMUzTFFpLg= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containers/gvisor-tap-vsock v0.4.0 h1:sPu8OWiboCBJE/VJyxKOikslCI3sAApNfl3jPXdzBRw= +github.com/containers/gvisor-tap-vsock v0.4.0/go.mod h1:2daFkw9Qp3NTz7+SLEIeSEZsQbxvJVoPVF5WtRy7h/4= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/stream-metadata-go v0.3.0/go.mod h1:RTjQyHgO/G37oJ3qnqYK6Z4TPZ5EsaabOtfMjVXmgko= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libcontainer v2.2.1+incompatible h1:++SbbkCw+X8vAd4j2gOCzZ2Nn7s2xFALTf7LZKmM1/0= github.com/docker/libcontainer v2.2.1+incompatible/go.mod h1:osvj61pYsqhNCMLGX31xr7klUBhHb/ZBuXS0o1Fvwbw= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/tcpproxy v0.0.0-20200125044825-b6bb9b5b8252/go.mod h1:DavVbd41y+b7ukKDmlnPR4nGYmkWXR6vHUkjQNiHPBs= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703 h1:oTi0zYvHo1sfk5sevGc4LrfgpLYB6cIhP/HllCUGcZ8= github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703/go.mod h1:ycRhVmo6wegyEl6WN+zXOHUTJvB0J2tiuH88q/McTK8= github.com/hf/nsm v0.0.0-20211106132757-1ae65a6a69ae h1:oCc+sRCVfMs1iL5yr7zen5K4+HNp4s/jHr+C9TacpWQ= github.com/hf/nsm v0.0.0-20211106132757-1ae65a6a69ae/go.mod h1:MJsac5D0fKcNWfriUERtln6segcGfD6Nu0V5uGBbPf8= +github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9 h1:pU32bJGmZwF4WXb9Yaz0T8vHDtIPVxqDOdmYdwTQPqw= +github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9/go.mod h1:MJsac5D0fKcNWfriUERtln6segcGfD6Nu0V5uGBbPf8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/insomniacslk/dhcp v0.0.0-20210812084645-decc701b3665/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3 h1:jUp75lepDg0phMUJBCmvaeFDldD2N3S1lBuPwUTszio= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= +github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 h1:DZMFueDbfz6PNc1GwDRA8+6lBx1TB9UnxDQliCqR73Y= +github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2/go.mod h1:SWzULI85WerrFt3u+nIm5F9l7EvxZTKQvd0InF3nmgM= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= github.com/mdlayher/vsock v1.1.1 h1:8lFuiXQnmICBrCIIA9PMgVSke6Fg6V4+r0v7r55k88I= github.com/mdlayher/vsock v1.1.1/go.mod h1:Y43jzcy7KM3QB+/FK15pfqGxDMCMzUXWegEfIbSM18U= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/milosgajdos/tenus v0.0.3 h1:jmaJzwaY1DUyYVD0lM4U+uvP2kkEg1VahDqRFxIkVBE= github.com/milosgajdos/tenus v0.0.3/go.mod h1:eIjx29vNeDOYWJuCnaHY2r4fq5egetV26ry3on7p8qY= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w= +github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY= +github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= +github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= +github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 h1:nn7SOQy8xCu3iXNv7oiBhhEQtbWdnEOMnuKBlHvrqIM= +github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 h1:vJ2V3lFLg+bBhgroYuRfyN583UzVveQmIXjc8T/y3to= golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220811182439-13a9a731de15 h1:cik0bxZUSJVDyaHf1hZPSDsU8SZHGQZQMeueXCE7yBQ= golang.org/x/net v0.0.0-20220811182439-13a9a731de15/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105210202-9ed45478a130/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gvisor.dev/gvisor v0.0.0-20220121190119-4f2d380c8b55/go.mod h1:vmN0Pug/s8TJmpnt30DvrEfZ5vDl52psGLU04tFuK2U= +gvisor.dev/gvisor v0.0.0-20221020012913-c40f8e36517d h1:MnKVuMlyvCL/phtPMbHDRrSItO2Mfd6GkWKLgbXOkpE= +gvisor.dev/gvisor v0.0.0-20221020012913-c40f8e36517d/go.mod h1:D0iRe6RVONyvN6uEi/rqBtONyitX5GaHMDDbeMzwgiE= +gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf h1:odIYzLMj6x99QKT69c6O8Cc3BNas3oUZPPw74hUzsS0= +gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf/go.mod h1:D0iRe6RVONyvN6uEi/rqBtONyitX5GaHMDDbeMzwgiE= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.16.13/go.mod h1:QWu8UWSTiuQZMMeYjwLs6ILu5O74qKSJ0c+4vrchDxs= +k8s.io/apimachinery v0.16.13/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ= +k8s.io/apimachinery v0.16.14-rc.0/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ= +k8s.io/client-go v0.16.13/go.mod h1:UKvVT4cajC2iN7DCjLgT0KVY/cbY6DGdUCyRiIfws5M= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/kube-openapi v0.0.0-20200410163147-594e756bea31/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/proxy.go b/proxy.go new file mode 100644 index 0000000..af17c57 --- /dev/null +++ b/proxy.go @@ -0,0 +1,212 @@ +package nitriding + +// Code mostly taken from: +// https://github.com/containers/gvisor-tap-vsock/blob/main/cmd/vm/main_linux.go + +import ( + "encoding/binary" + "fmt" + "io" + "net" + "net/http" + "os" + "os/exec" + + "github.com/containers/gvisor-tap-vsock/pkg/transport" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + "github.com/songgao/packets/ethernet" + "github.com/songgao/water" + "github.com/vishvananda/netlink" + "gvisor.dev/gvisor/pkg/tcpip/header" +) + +var ( + endpoint = fmt.Sprintf("vsock://%d:1024/connect", parentCID) + iface = "tap0" + mac = "5a:94:ef:e4:0c:ee" + debug = true + mtu = 4000 +) + +/* +func main() { + flag.StringVar(&endpoint, "url", fmt.Sprintf("vsock://2:1024%s", types.ConnectPath), "url where the tap send packets") + flag.StringVar(&iface, "iface", "tap0", "tap interface name") + flag.StringVar(&stopIfIfaceExist, "stop-if-exist", "eth0,ens3,enp0s1", "stop if one of these interfaces exists at startup") + flag.StringVar(&mac, "mac", "5a:94:ef:e4:0c:ee", "mac address") + flag.BoolVar(&debug, "debug", false, "debug") + flag.IntVar(&mtu, "mtu", 4000, "mtu") + flag.Parse() + + expected := strings.Split(stopIfIfaceExist, ",") + links, err := netlink.LinkList() + if err != nil { + log.Fatal(err) + } + for _, link := range links { + if contains(expected, link.Attrs().Name) { + log.Infof("interface %s prevented this program to run", link.Attrs().Name) + return + } + } + for { + if err := run(); err != nil { + log.Error(err) + } + time.Sleep(time.Second) + } +} +*/ + +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} + +func setupProxy(c *Config) error { + conn, path, err := transport.Dial(endpoint) + if err != nil { + return errors.Wrap(err, "cannot connect to host") + } + defer conn.Close() + + req, err := http.NewRequest("POST", path, nil) + if err != nil { + return err + } + if err := req.Write(conn); err != nil { + return err + } + + tap, err := water.New(water.Config{ + DeviceType: water.TAP, + PlatformSpecificParams: water.PlatformSpecificParams{ + Name: iface, + }, + }) + if err != nil { + return errors.Wrap(err, "cannot create tap device") + } + defer tap.Close() + + if err := linkUp(); err != nil { + return errors.Wrap(err, "cannot set mac address") + } + + errCh := make(chan error, 1) + go tx(conn, tap, errCh, mtu) + go rx(conn, tap, errCh, mtu) + go func() { + if err := dhcp(); err != nil { + errCh <- errors.Wrap(err, "dhcp error") + } + }() + return <-errCh +} + +func linkUp() error { + link, err := netlink.LinkByName(iface) + if err != nil { + return err + } + if mac == "" { + return netlink.LinkSetUp(link) + } + hw, err := net.ParseMAC(mac) + if err != nil { + return err + } + if err := netlink.LinkSetHardwareAddr(link, hw); err != nil { + return err + } + return netlink.LinkSetUp(link) +} + +func dhcp() error { + if _, err := exec.LookPath("udhcpc"); err == nil { // busybox dhcp client + cmd := exec.Command("udhcpc", "-f", "-q", "-i", iface, "-v") + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + return cmd.Run() + } + cmd := exec.Command("dhclient", "-4", "-d", "-v", iface) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + return cmd.Run() +} + +func rx(conn net.Conn, tap *water.Interface, errCh chan error, mtu int) { + log.Info("waiting for packets...") + var frame ethernet.Frame + for { + frame.Resize(mtu) + n, err := tap.Read([]byte(frame)) + if err != nil { + errCh <- errors.Wrap(err, "cannot read packet from tap") + return + } + frame = frame[:n] + + if debug { + packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default) + log.Info(packet.String()) + } + + size := make([]byte, 2) + binary.LittleEndian.PutUint16(size, uint16(n)) + + if _, err := conn.Write(size); err != nil { + errCh <- errors.Wrap(err, "cannot write size to socket") + return + } + if _, err := conn.Write(frame); err != nil { + errCh <- errors.Wrap(err, "cannot write packet to socket") + return + } + } +} + +func tx(conn net.Conn, tap *water.Interface, errCh chan error, mtu int) { + sizeBuf := make([]byte, 2) + buf := make([]byte, mtu+header.EthernetMinimumSize) + + for { + n, err := io.ReadFull(conn, sizeBuf) + if err != nil { + errCh <- errors.Wrap(err, "cannot read size from socket") + return + } + if n != 2 { + errCh <- fmt.Errorf("unexpected size %d", n) + return + } + size := int(binary.LittleEndian.Uint16(sizeBuf[0:2])) + + n, err = io.ReadFull(conn, buf[:size]) + if err != nil { + errCh <- errors.Wrap(err, "cannot read payload from socket") + return + } + if n == 0 || n != size { + errCh <- fmt.Errorf("unexpected size %d != %d", n, size) + return + } + + if debug { + packet := gopacket.NewPacket(buf[:size], layers.LayerTypeEthernet, gopacket.Default) + log.Info(packet.String()) + } + + if _, err := tap.Write(buf[:size]); err != nil { + errCh <- errors.Wrap(err, "cannot write packet to tap") + return + } + } +} From 772c1db251f672552074ca36a6d39adf239002bb Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 20 Oct 2022 09:31:35 -0500 Subject: [PATCH 02/55] Add executable. ...because nitriding is no longer (just) a package. --- cmd/main.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 cmd/main.go diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..9ba08ef --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "log" + "os" + + "github.com/brave/nitriding" +) + +func main() { + log.Printf("Running as UID %d.", os.Getuid()) + + enclave := nitriding.NewEnclave( + &nitriding.Config{ + FQDN: "nitro.nymity.ch", + Port: 8080, + UseACME: false, + Debug: true, + }, + ) + + // Start blocks for as long as the enclave is alive. + if err := enclave.Start(); err != nil { + log.Fatalf("Enclave terminated: %v", err) + } +} From 63533c0c4884c77fc703694144961f35d7ad609a Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 21 Oct 2022 09:03:42 -0500 Subject: [PATCH 03/55] Add config validation step. --- cmd/main.go | 5 ++++- enclave.go | 33 ++++++++++++++++++++++++++------- enclave_test.go | 27 ++++++++++++++++++++++++++- keysync_responder_test.go | 10 +++++----- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 9ba08ef..b2b8fb0 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -10,7 +10,7 @@ import ( func main() { log.Printf("Running as UID %d.", os.Getuid()) - enclave := nitriding.NewEnclave( + enclave, err := nitriding.NewEnclave( &nitriding.Config{ FQDN: "nitro.nymity.ch", Port: 8080, @@ -18,6 +18,9 @@ func main() { Debug: true, }, ) + if err != nil { + log.Fatal(err) + } // Start blocks for as long as the enclave is alive. if err := enclave.Start(); err != nil { diff --git a/enclave.go b/enclave.go index f60da29..19782bd 100644 --- a/enclave.go +++ b/enclave.go @@ -50,9 +50,11 @@ const ( ) var ( - elog = log.New(os.Stderr, "nitriding: ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile) - inEnclave = false - errNoKeyMaterial = errors.New("no key material registered") + elog = log.New(os.Stderr, "nitriding: ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile) + inEnclave = false + errNoKeyMaterial = errors.New("no key material registered") + errCfgMissingFQDN = errors.New("given config is missing FQDN") + errCfgMissingPort = errors.New("given config is missing port") ) // Enclave represents a service running inside an AWS Nitro Enclave. @@ -77,12 +79,14 @@ type Config struct { SOCKSProxy string // FQDN contains the fully qualified domain name that's set in the HTTPS - // certificate of the enclave's Web server, e.g. "example.com". + // certificate of the enclave's Web server, e.g. "example.com". This field + // is required. FQDN string // Port contains the TCP port that the Web server should listen on, e.g. // 8443. Note that the Web server listens for this port on the private - // VSOCK interface. This is not an Internet-facing port. + // VSOCK interface. This is not an Internet-facing port. This field is + // required. Port int // UseACME must be set to true if you want your enclave application to @@ -113,6 +117,17 @@ type Config struct { AppURL string } +// Validate returns an error if required fields in the config are not set. +func (c *Config) Validate() error { + if c.FQDN == "" { + return errCfgMissingFQDN + } + if c.Port == 0 { + return errCfgMissingPort + } + return nil +} + // init is called once, at package initialization time. func init() { var err error @@ -127,7 +142,11 @@ func init() { } // NewEnclave creates and returns a new enclave with the given config. -func NewEnclave(cfg *Config) *Enclave { +func NewEnclave(cfg *Config) (*Enclave, error) { + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("failed to create enclave: %w", err) + } + r := chi.NewRouter() e := &Enclave{ cfg: cfg, @@ -142,7 +161,7 @@ func NewEnclave(cfg *Config) *Enclave { e.router.Use(middleware.Logger) } - return e + return e, nil } // Start starts the Nitro Enclave. If it bootstraps correctly, this function diff --git a/enclave_test.go b/enclave_test.go index 7574c67..a1e660e 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -19,7 +19,32 @@ func createEnclave() *Enclave { FdCur: 1024, FdMax: 4096, } - return NewEnclave(cfg) + e, err := NewEnclave(cfg) + if err != nil { + panic(err) + } + return e +} + +func TestValidateConfig(t *testing.T) { + var err error + var c Config + + if err = c.Validate(); err == nil { + t.Fatalf("Validation of invalid config did not return an error.") + } + + // Set one required field but leave others unset. + c.FQDN = "example.com" + if err = c.Validate(); err == nil { + t.Fatalf("Validation of invalid config did not return an error.") + } + + // Set the last required field. + c.Port = 1 + if err = c.Validate(); err != nil { + t.Fatalf("Validation of valid config returned an error.") + } } func TestGenSelfSignedCert(t *testing.T) { diff --git a/keysync_responder_test.go b/keysync_responder_test.go index 7d69c01..77a9595 100644 --- a/keysync_responder_test.go +++ b/keysync_responder_test.go @@ -24,7 +24,7 @@ func queryHandler(handler http.HandlerFunc, path string, reader io.Reader) *http } func TestNonceHandler(t *testing.T) { - enclave := NewEnclave(&Config{}) + enclave := createEnclave() res := queryHandler(getNonceHandler(enclave), pathNonce, bytes.NewReader([]byte{})) // Did the operation succeed? @@ -57,7 +57,7 @@ func TestNonceHandlerIfErr(t *testing.T) { cryptoRead = rand.Read }() - res := queryHandler(getNonceHandler(NewEnclave(&Config{})), pathNonce, bytes.NewReader([]byte{})) + res := queryHandler(getNonceHandler(createEnclave()), pathNonce, bytes.NewReader([]byte{})) // Did the operation fail? if res.StatusCode != http.StatusInternalServerError { @@ -74,7 +74,7 @@ func TestNonceHandlerIfErr(t *testing.T) { func TestKeysHandlerForBadReqs(t *testing.T) { var res *http.Response - enclave := NewEnclave(&Config{}) + enclave := createEnclave() // Send non-Base64 bogus data. res = queryHandler(getKeysHandler(enclave, time.Now), pathKeys, strings.NewReader("foobar!")) @@ -87,7 +87,7 @@ func TestKeysHandlerForBadReqs(t *testing.T) { func TestKeysHandler(t *testing.T) { var res *http.Response - enclave := NewEnclave(&Config{}) + enclave := createEnclave() enclave.nonceCache.Add(initAttInfo.nonce.B64()) // Mock functions for our tests to pass. @@ -104,7 +104,7 @@ func TestKeysHandler(t *testing.T) { func TestKeysHandlerDoS(t *testing.T) { var res *http.Response - enclave := NewEnclave(&Config{}) + enclave := createEnclave() // Send more data than the handler should be willing to read. maxSize := base64.StdEncoding.EncodedLen(maxAttDocLen) From 95c1aab33c5d681f3b4337e95c62910c16a0abc0 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 09:16:56 -0500 Subject: [PATCH 04/55] Add system architecture diagram. --- README.md | 4 ++++ doc/architecture.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 doc/architecture.md diff --git a/README.md b/README.md index e18df51..7c48f22 100644 --- a/README.md +++ b/README.md @@ -99,3 +99,7 @@ To test and lint the code, run: ``` make ``` + +## More documentation + +* [System architecture](doc/architecture.md) diff --git a/doc/architecture.md b/doc/architecture.md new file mode 100644 index 0000000..7fc4a29 --- /dev/null +++ b/doc/architecture.md @@ -0,0 +1,42 @@ +```mermaid +sequenceDiagram + actor client as Client + participant ca as Let's Encrypt + participant ec2 as EC2 host + participant nitriding as Nitriding + participant app as Enclave application + +ec2->>ec2: Set up proxy + +Note over ec2,app: Enclave setup starts + +nitriding->>ec2: Establish TAP tunnel +nitriding->>nitriding: Set up Web servers +app->>app: Set up Web server + +Note over nitriding,app: Only necessary when scaling enclaves. + +opt Register key material + app->>+nitriding: PUT /post-keys + nitriding-->>-app: OK +end + +nitriding->>+ec2: Packet forwarding +ec2->>+ca: Request HTTPS certificate (via HTTP-01) +ca-->>-ec2: HTTPS certificate +ec2-->>-nitriding: Packet forwarding + +Note over ec2,app: Enclave setup finished + +client->>+ec2: GET /attestation?nonce=foobar +ec2->>+nitriding: Packet forwarding +nitriding-->>-ec2: Packet forwarding +ec2-->>-client: Attestation document + +client->>client: Verify attestation document + +client->>+ec2: GET /hello +ec2->>+app: Packet forwarding +app-->>-ec2: Packet forwarding +ec2-->>-client: "Hello world!" +``` From 63faf97ff4809572abf8d3fa622a5b54bbfe1218 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 11:22:34 -0500 Subject: [PATCH 05/55] Add handler that allows for secret registration. Nitriding is going to be running two Web servers: one is public-facing and meant to be accessed by clients and the other is enclave-facing and meant to be accessed by the enclave application. --- handlers.go | 27 +++++++++++++++++++++++++++ handlers_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 handlers_test.go diff --git a/handlers.go b/handlers.go index 2af6ed6..32c75b2 100644 --- a/handlers.go +++ b/handlers.go @@ -1,10 +1,22 @@ package nitriding import ( + "errors" "fmt" + "io" "net/http" ) +const ( + // The maximum length of the key material (in bytes) that enclave + // applications can PUT to our HTTP API. + maxKeyMaterialLen = 1024 * 1024 +) + +var ( + errFailedReqBody = errors.New("failed to read request body") +) + func formatIndexPage(appURL string) string { page := "This host runs inside an AWS Nitro Enclave.\n" if appURL != "" { @@ -22,3 +34,18 @@ func getIndexHandler(cfg *Config) http.HandlerFunc { fmt.Fprintln(w, formatIndexPage(cfg.AppURL)) } } + +// getRegisterKeysHandler returns a handler that lets the enclave application +// register its key material with nitriding. The key material can be arbitrary +// bytes. +func getRegisterKeysHandler(e *Enclave) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(newLimitReader(r.Body, maxKeyMaterialLen)) + if err != nil { + http.Error(w, errFailedReqBody.Error(), http.StatusInternalServerError) + return + } + e.SetKeyMaterial(body) + w.WriteHeader(http.StatusOK) + } +} diff --git a/handlers_test.go b/handlers_test.go new file mode 100644 index 0000000..b3d54e9 --- /dev/null +++ b/handlers_test.go @@ -0,0 +1,39 @@ +package nitriding + +import ( + "bytes" + "net/http" + "net/http/httptest" + "testing" +) + +func TestGetRegisterKeysHandler(t *testing.T) { + expected := []byte{1, 2, 3, 4, 5} // The key material that we're setting and retrieving. + e := createEnclave() + handler := getRegisterKeysHandler(e) + rec := httptest.NewRecorder() + req, err := http.NewRequest(http.MethodPut, pathPostKeys, bytes.NewReader(expected)) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + + handler(rec, req) + resp := rec.Result() + + // As long as we don't hit our (generous) upload limit, we always expect an + // HTTP 200 response. + if resp.StatusCode != http.StatusOK { + t.Fatalf("Expected HTTP status code %d but got %d.", http.StatusOK, resp.StatusCode) + } + + // Make sure that the key material was set in the enclave. + m, err := e.KeyMaterial() + if err != nil { + t.Fatalf("Failed to obtain enclave key material: %v", err) + } + retrieved := m.([]byte) + + if !bytes.Equal(retrieved, expected) { + t.Fatalf("Expected %q but got %q.", expected, retrieved) + } +} From 3ffa59d6c9a12469fd760b4a6cb5c002c9af1d5e Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 11:34:28 -0500 Subject: [PATCH 06/55] Add Makefile and refactor standalone application. --- cmd/Makefile | 15 +++++++++++++++ cmd/main.go | 29 ++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 cmd/Makefile diff --git a/cmd/Makefile b/cmd/Makefile new file mode 100644 index 0000000..670c5f9 --- /dev/null +++ b/cmd/Makefile @@ -0,0 +1,15 @@ +.PHONY: all lint clean + +binary = nitriding +godeps = *.go + +all: lint $(binary) + +lint: + golangci-lint run + +$(binary): $(godeps) + go build -o $(binary) + +clean: + rm $(binary) diff --git a/cmd/main.go b/cmd/main.go index b2b8fb0..3c8191e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,29 +1,44 @@ package main import ( + "flag" "log" "os" "github.com/brave/nitriding" ) +var l = log.New(os.Stderr, "nitriding-cmd: ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile) + func main() { - log.Printf("Running as UID %d.", os.Getuid()) + var sockAddr, fqdn, appURL string + var port, hostProxyPort int + var useACME bool + + flag.StringVar(&fqdn, "fqdn", "example.com", "FQDN for the enclave application.") + flag.StringVar(&sockAddr, "sockaddr", "/tmp/nitriding.sock", "Path to unix domain socket for enclave-internal IPC.") + flag.StringVar(&appURL, "appurl", "github.com/foo/bar", "Code repository for the enclave application.") + flag.IntVar(&port, "port", 8443, "Nitriding's VSOCK-facing HTTP port. Must match port forwarding rules on EC2 host.") + flag.IntVar(&hostProxyPort, "host-proxy-port", 1024, "Port of proxy application running on EC2 host.") + flag.BoolVar(&useACME, "acme", true, "Use Let's Encrypt's ACME to fetch HTTPS certificate.") + flag.Parse() enclave, err := nitriding.NewEnclave( &nitriding.Config{ - FQDN: "nitro.nymity.ch", - Port: 8080, - UseACME: false, - Debug: true, + FQDN: fqdn, + Port: port, + HostProxyPort: hostProxyPort, + UseACME: useACME, + SockAddr: sockAddr, + AppURL: appURL, }, ) if err != nil { - log.Fatal(err) + l.Fatalf("Failed to create enclave: %v", err) } // Start blocks for as long as the enclave is alive. if err := enclave.Start(); err != nil { - log.Fatalf("Enclave terminated: %v", err) + l.Fatalf("Enclave terminated: %v", err) } } From 523667b36d4f94d29d8d4a8d01b5402dff63625c Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 11:34:57 -0500 Subject: [PATCH 07/55] Add .gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..01ed2ab --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +cmd/nitriding From d2b9202c9272ae981a8c2cda5692c9814def70bc Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 14:50:56 -0500 Subject: [PATCH 08/55] Add target to build nitriding executable. --- Makefile | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 45b7b67..716f8f0 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,18 @@ -.PHONY: all test lint +.PHONY: all test lint clean +binary = cmd/nitriding godeps = *.go go.mod go.sum -all: test lint +all: test lint $(binary) lint: golangci-lint run test: $(godeps) @go test -cover ./... + +$(binary): $(godeps) + make -C cmd/ + +clean: + make -C cmd/ clean From 21d68c85149d7c75562431ab223b660e923aa94c Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 16:39:49 -0500 Subject: [PATCH 09/55] Add function for creating a unix domain socket. --- system.go | 17 +++++++++++++++++ system_test.go | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/system.go b/system.go index 2471ce1..1ae2ed7 100644 --- a/system.go +++ b/system.go @@ -3,6 +3,8 @@ package nitriding import ( "errors" "io" + "net" + "os" "syscall" ) @@ -77,3 +79,18 @@ func setFdLimit(cur, max uint64) error { return nil } + +// createUnixSocket creates a unix domain socket at the given path and returns +// a listener for it. +func createUnixSocket(sockaddr string) (net.Listener, error) { + if err := os.RemoveAll(sockaddr); err != nil { + return nil, err + } + + l, err := net.Listen("unix", sockaddr) + if err != nil { + return nil, err + } + + return l, nil +} diff --git a/system_test.go b/system_test.go index ee6b309..f946521 100644 --- a/system_test.go +++ b/system_test.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "io" + "os" "syscall" "testing" ) @@ -84,3 +85,16 @@ func TestSetFdLimit(t *testing.T) { } checkFdLimit(t, defaultFdCur-1, defaultFdMax-1) } + +func TestCreateUnixSocket(t *testing.T) { + fd, err := os.CreateTemp("/tmp", "domainsock") + if err != nil { + t.Fatalf("Failed to create temporary file: %v", err) + } + defer os.Remove(fd.Name()) + + _, err = createUnixSocket(fd.Name()) + if err != nil { + t.Fatalf("Failed to create unix socket: %v", err) + } +} From 755834f03238c9ab2df2d5717d9b90d44ae4c2dc Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 16:55:44 -0500 Subject: [PATCH 10/55] Refactor. --- enclave.go | 169 +++++++++++++++----------------------- enclave_test.go | 13 ++- go.mod | 1 + go.sum | 2 + keysync_initiator.go | 2 +- keysync_responder_test.go | 8 +- proxy.go | 119 ++++++++++----------------- system_darwin.go | 3 - system_linux.go | 27 ------ 9 files changed, 124 insertions(+), 220 deletions(-) delete mode 100644 system_darwin.go delete mode 100644 system_linux.go diff --git a/enclave.go b/enclave.go index 19782bd..2a1db14 100644 --- a/enclave.go +++ b/enclave.go @@ -16,36 +16,30 @@ import ( "fmt" "log" "math/big" - "net" "net/http" - "net/url" "os" "sync" "time" + "github.com/go-chi/chi/middleware" "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" - "github.com/mdlayher/vsock" "github.com/brave/nitriding/randseed" - "github.com/brave/viproxy" "golang.org/x/crypto/acme/autocert" ) const ( acmeCertCacheDir = "cert-cache" - certificateOrg = "Brave Software" + certificateOrg = "AWS Nitro enclave application" certificateValidity = time.Hour * 24 * 356 // parentCID determines the CID (analogous to an IP address) of the parent // EC2 instance. According to the AWS docs, it is always 3: // https://docs.aws.amazon.com/enclaves/latest/user/nitro-enclave-concepts.html - parentCID = 3 - // parentProxyPort determines the TCP port of the SOCKS proxy that's - // running on the parent EC2 instance. - parentProxyPort = 1080 + parentCID = 3 pathNonce = "/nonce" pathAttestation = "/attestation" - pathKeys = "/keys" + pathGetKeys = "/get-keys" + pathPostKeys = "/post-keys" pathRoot = "/" ) @@ -60,24 +54,15 @@ var ( // Enclave represents a service running inside an AWS Nitro Enclave. type Enclave struct { sync.RWMutex - cfg *Config - httpSrv http.Server - router *chi.Mux - certFpr [sha256.Size]byte - nonceCache *cache - keyMaterial any + cfg *Config + pubSrv, privSrv http.Server + certFpr [sha256.Size]byte + nonceCache *cache + keyMaterial any } // Config represents the configuration of our enclave service. type Config struct { - // SOCKSProxy must be set if - // 1) your enclave application should obtain a Let's Encrypt-signed - // certificate (i.e., if UseACME is set to true) - // or if - // 2) your enclave application makes HTTP requests over the Internet. - // If so, set SOCKSProxy to "socks5://127.0.0.1:1080". - SOCKSProxy string - // FQDN contains the fully qualified domain name that's set in the HTTPS // certificate of the enclave's Web server, e.g. "example.com". This field // is required. @@ -89,6 +74,14 @@ type Config struct { // required. Port int + // HostProxyPort indicates the TCP port of the proxy application running on + // the EC2 host. If unset, the default of 1024 is goint to be used. + HostProxyPort int + + // SockAddr indicates the file system path to the Unix domain socket that + // enclave applications can use to talk to nitriding's HTTP API. + SockAddr string + // UseACME must be set to true if you want your enclave application to // request a Let's Encrypt-signed certificate. If this is set to false, // the enclave creates a self-signed certificate. @@ -147,18 +140,30 @@ func NewEnclave(cfg *Config) (*Enclave, error) { return nil, fmt.Errorf("failed to create enclave: %w", err) } - r := chi.NewRouter() e := &Enclave{ - cfg: cfg, - router: r, - httpSrv: http.Server{ + cfg: cfg, + pubSrv: http.Server{ Addr: fmt.Sprintf(":%d", cfg.Port), - Handler: r, + Handler: chi.NewRouter(), + }, + privSrv: http.Server{ + Handler: chi.NewRouter(), }, nonceCache: newCache(defaultItemExpiry), } + // Register public HTTP API. + m := e.pubSrv.Handler.(*chi.Mux) + m.Get(pathAttestation, getAttestationHandler(&e.certFpr)) + m.Get(pathNonce, getNonceHandler(e)) + m.Get(pathGetKeys, getKeysHandler(e, time.Now)) + m.Get(pathRoot, getIndexHandler(e.cfg)) + // Register enclave-internal HTTP API. + m = e.privSrv.Handler.(*chi.Mux) + m.Put(pathPostKeys, getRegisterKeysHandler(e)) + if cfg.Debug { - e.router.Use(middleware.Logger) + e.pubSrv.Handler.(*chi.Mux).Use(middleware.Logger) + e.privSrv.Handler.(*chi.Mux).Use(middleware.Logger) } return e, nil @@ -171,21 +176,15 @@ func (e *Enclave) Start() error { var err error errPrefix := "failed to start Nitro Enclave" - if inEnclave { - if err = assignLoAddr(); err != nil { - return fmt.Errorf("%s: failed to assign loopback address: %w", errPrefix, err) - } - elog.Println("Assigned address to lo interface.") - } - // Set file descriptor limit. There's no need to exit if this fails. if err = setFdLimit(e.cfg.FdCur, e.cfg.FdMax); err != nil { elog.Printf("Failed to set new file descriptor limit: %s", err) } - // Set up proxy that facilitates communication with the host. - if err = setupProxy(e.cfg); err != nil { - elog.Fatal(err) + // Set up our networking environment which creates a TAP device that + // forwards traffic (via the VSOCK interface) to the EC2 host. + if err = setupNetworking(e.cfg); err != nil { + return fmt.Errorf("%s: failed to set up proxying: %w", errPrefix, err) } // Get an HTTPS certificate. @@ -197,64 +196,27 @@ func (e *Enclave) Start() error { if err != nil { return fmt.Errorf("%s: failed to create certificate: %w", errPrefix, err) } - if inEnclave { - e.router.Get(pathAttestation, getAttestationHandler(&e.certFpr)) - } - e.router.Get(pathNonce, getNonceHandler(e)) - e.router.Get(pathRoot, getIndexHandler(e.cfg)) - e.router.Post(pathKeys, getKeysHandler(e, time.Now)) - - // Tell Go's HTTP library to use SOCKS proxy for both HTTP and HTTPS. - if err := os.Setenv("HTTP_PROXY", e.cfg.SOCKSProxy); err != nil { - return fmt.Errorf("%s: failed to set env var: %w", errPrefix, err) - } - if err := os.Setenv("HTTPS_PROXY", e.cfg.SOCKSProxy); err != nil { - return fmt.Errorf("%s: failed to set env var: %w", errPrefix, err) - } - // Set up AF_INET to AF_VSOCK proxy to facilitate the use of the SOCKS - // proxy. - u, err := url.Parse(e.cfg.SOCKSProxy) - if err != nil { - return fmt.Errorf("failed to parse SOCKSProxy from config: %w", err) - } - inAddr, err := net.ResolveTCPAddr("tcp", u.Host) - if err != nil { - return fmt.Errorf("failed to resolve SOCKSProxy from config: %w", err) - } - tuple := &viproxy.Tuple{ - InAddr: inAddr, - OutAddr: &vsock.Addr{ContextID: uint32(parentCID), Port: uint32(parentProxyPort)}, - } - proxy := viproxy.NewVIProxy([]*viproxy.Tuple{tuple}) - if err := proxy.Start(); err != nil { - return fmt.Errorf("failed to start VIProxy: %w", err) + if err = startWebServers(e); err != nil { + return fmt.Errorf("%s: %w", errPrefix, err) } - elog.Printf("Starting Web server on port %s.", e.httpSrv.Addr) - var l net.Listener + return nil +} - // Finally, start the Web server. If we're inside an enclave, we use a - // vsock-enabled listener, otherwise a simple tcp listener. - if inEnclave { - l, err = vsock.Listen(uint32(e.cfg.Port), nil) - if err != nil { - return fmt.Errorf("%s: failed to create vsock listener: %w", errPrefix, err) - } - defer func() { - _ = l.Close() - }() +// startWebServers starts both our public-facing and our enclave-internal Web +// server in a goroutine. +func startWebServers(e *Enclave) error { + elog.Printf("Starting public (%s) and private (%s) Web server.", e.pubSrv.Addr, e.privSrv.Addr) - return e.httpSrv.ServeTLS(l, "", "") - } - l, err = net.Listen("tcp", e.httpSrv.Addr) + l, err := createUnixSocket(e.cfg.SockAddr) if err != nil { - return fmt.Errorf("%s: failed to create tcp listener: %w", errPrefix, err) + return fmt.Errorf("failed to create unix domain socket: %w", err) } - defer func() { - _ = l.Close() - }() - return e.httpSrv.ServeTLS(l, "", "") + go e.privSrv.Serve(l) //nolint:errcheck + go e.pubSrv.ListenAndServeTLS("", "") //nolint:errcheck + + return nil } // genSelfSignedCert creates and returns a self-signed TLS certificate based on @@ -317,7 +279,7 @@ func (e *Enclave) genSelfSignedCert() error { return err } - e.httpSrv.TLSConfig = &tls.Config{ + e.pubSrv.TLSConfig = &tls.Config{ Certificates: []tls.Certificate{cert}, } @@ -355,7 +317,7 @@ func (e *Enclave) setupAcme() error { return err } - e.httpSrv.TLSConfig = &tls.Config{GetCertificate: certManager.GetCertificate} + e.pubSrv.TLSConfig = &tls.Config{GetCertificate: certManager.GetCertificate} go func() { // Wait until the HTTP-01 listener returned and then check if our new @@ -409,25 +371,26 @@ func (e *Enclave) setCertFingerprint(rawData []byte) error { // AddRoute adds an HTTP handler for the given HTTP method and pattern. func (e *Enclave) AddRoute(method, pattern string, handlerFn http.HandlerFunc) { + r := e.pubSrv.Handler.(*chi.Mux) switch method { case http.MethodGet: - e.router.Get(pattern, handlerFn) + r.Get(pattern, handlerFn) case http.MethodHead: - e.router.Head(pattern, handlerFn) + r.Head(pattern, handlerFn) case http.MethodPost: - e.router.Post(pattern, handlerFn) + r.Post(pattern, handlerFn) case http.MethodPut: - e.router.Put(pattern, handlerFn) + r.Put(pattern, handlerFn) case http.MethodPatch: - e.router.Patch(pattern, handlerFn) + r.Patch(pattern, handlerFn) case http.MethodDelete: - e.router.Delete(pattern, handlerFn) + r.Delete(pattern, handlerFn) case http.MethodConnect: - e.router.Connect(pattern, handlerFn) + r.Connect(pattern, handlerFn) case http.MethodOptions: - e.router.Options(pattern, handlerFn) + r.Options(pattern, handlerFn) case http.MethodTrace: - e.router.Trace(pattern, handlerFn) + r.Trace(pattern, handlerFn) } } diff --git a/enclave_test.go b/enclave_test.go index a1e660e..49b46fc 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -11,13 +11,12 @@ import ( func createEnclave() *Enclave { cfg := &Config{ - SOCKSProxy: "socks5://127.0.0.1:1080", - FQDN: "example.com", - Port: 50000, - UseACME: false, - Debug: false, - FdCur: 1024, - FdMax: 4096, + FQDN: "example.com", + Port: 50000, + UseACME: false, + Debug: false, + FdCur: 1024, + FdMax: 4096, } e, err := NewEnclave(cfg) if err != nil { diff --git a/go.mod b/go.mod index b4f8fd1..c137b36 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/brave/viproxy v0.1.2 github.com/containers/gvisor-tap-vsock v0.4.0 + github.com/go-chi/chi v1.5.4 github.com/go-chi/chi/v5 v5.0.7 github.com/google/gopacket v1.1.19 github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703 diff --git a/go.sum b/go.sum index fe2e6cc..0e62faf 100644 --- a/go.sum +++ b/go.sum @@ -134,6 +134,8 @@ github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= +github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= diff --git a/keysync_initiator.go b/keysync_initiator.go index 514e43b..e684878 100644 --- a/keysync_initiator.go +++ b/keysync_initiator.go @@ -125,7 +125,7 @@ func requestNonce(addr string) (nonce, error) { func requestAttDoc(addr string, ourAttDoc []byte) ([]byte, error) { errStr := "failed to fetch attestation doc from remote enclave" - endpoint := fmt.Sprintf("%s%s", addr, pathKeys) + endpoint := fmt.Sprintf("%s%s", addr, pathGetKeys) // Finally, send our attestation document to the remote enclave. If // everything works out, the remote enclave is going to respond with its diff --git a/keysync_responder_test.go b/keysync_responder_test.go index 77a9595..ae7c224 100644 --- a/keysync_responder_test.go +++ b/keysync_responder_test.go @@ -77,11 +77,11 @@ func TestKeysHandlerForBadReqs(t *testing.T) { enclave := createEnclave() // Send non-Base64 bogus data. - res = queryHandler(getKeysHandler(enclave, time.Now), pathKeys, strings.NewReader("foobar!")) + res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, strings.NewReader("foobar!")) expect(t, res, http.StatusInternalServerError, errNoBase64.Error()) // Send Base64-encoded bogus data. - res = queryHandler(getKeysHandler(enclave, time.Now), pathKeys, strings.NewReader("Zm9vYmFyCg==")) + res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, strings.NewReader("Zm9vYmFyCg==")) expect(t, res, http.StatusUnauthorized, errFailedVerify.Error()) } @@ -96,7 +96,7 @@ func TestKeysHandler(t *testing.T) { } currentTime = func() time.Time { return initAttInfo.attDocTime } - res = queryHandler(getKeysHandler(enclave, time.Now), pathKeys, strings.NewReader(initAttInfo.attDoc)) + res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, strings.NewReader(initAttInfo.attDoc)) // On a non-enclave platform, the responder code will get as far as to // request its attestation document. expect(t, res, http.StatusInternalServerError, errFailedAttestation) @@ -109,7 +109,7 @@ func TestKeysHandlerDoS(t *testing.T) { // Send more data than the handler should be willing to read. maxSize := base64.StdEncoding.EncodedLen(maxAttDocLen) body := make([]byte, maxSize+1) - res = queryHandler(getKeysHandler(enclave, time.Now), pathKeys, bytes.NewReader(body)) + res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, bytes.NewReader(body)) expect(t, res, http.StatusInternalServerError, errFailedRespBody.Error()) } diff --git a/proxy.go b/proxy.go index af17c57..7c5bd74 100644 --- a/proxy.go +++ b/proxy.go @@ -13,10 +13,6 @@ import ( "os/exec" "github.com/containers/gvisor-tap-vsock/pkg/transport" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" "github.com/songgao/packets/ethernet" "github.com/songgao/water" "github.com/vishvananda/netlink" @@ -24,88 +20,70 @@ import ( ) var ( - endpoint = fmt.Sprintf("vsock://%d:1024/connect", parentCID) - iface = "tap0" - mac = "5a:94:ef:e4:0c:ee" - debug = true - mtu = 4000 + mtu = 4000 ) -/* -func main() { - flag.StringVar(&endpoint, "url", fmt.Sprintf("vsock://2:1024%s", types.ConnectPath), "url where the tap send packets") - flag.StringVar(&iface, "iface", "tap0", "tap interface name") - flag.StringVar(&stopIfIfaceExist, "stop-if-exist", "eth0,ens3,enp0s1", "stop if one of these interfaces exists at startup") - flag.StringVar(&mac, "mac", "5a:94:ef:e4:0c:ee", "mac address") - flag.BoolVar(&debug, "debug", false, "debug") - flag.IntVar(&mtu, "mtu", 4000, "mtu") - flag.Parse() - - expected := strings.Split(stopIfIfaceExist, ",") - links, err := netlink.LinkList() - if err != nil { - log.Fatal(err) - } - for _, link := range links { - if contains(expected, link.Attrs().Name) { - log.Infof("interface %s prevented this program to run", link.Attrs().Name) - return - } - } - for { - if err := run(); err != nil { - log.Error(err) - } - time.Sleep(time.Second) - } -} -*/ - -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} +const ( + // iface indicates the name of our enclave-internal TAP device. + iface = "tap0" + // mac indicates the MAC address of the enclave. + mac = "5a:94:ef:e4:0c:ee" +) -func setupProxy(c *Config) error { +// setupNetworking sets up the enclave's networking environment. In +// particular, this function: +// +// 1. Creates a TAP device. +// 2. Set up networking links. +// 3. Establish a connection with the proxy running on the host. +// 4. Run DHCP to obtain an IP address. +// 5. Spawn goroutines to forward traffic between the TAP device and the proxy +// running on the host. +func setupNetworking(c *Config) error { + elog.Println("Setting up networking between host and enclave.") + defer elog.Println("Tearing down networking between host and enclave.") + + // Establish connection with the proxy running on the EC2 host. + endpoint := fmt.Sprintf("vsock://%d:%d/connect", parentCID, c.HostProxyPort) conn, path, err := transport.Dial(endpoint) if err != nil { - return errors.Wrap(err, "cannot connect to host") + return fmt.Errorf("failed to connect to host: %w", err) } defer conn.Close() - req, err := http.NewRequest("POST", path, nil) + req, err := http.NewRequest(http.MethodPost, path, nil) if err != nil { - return err + return fmt.Errorf("failed to create POST request: %w", err) } if err := req.Write(conn); err != nil { - return err + return fmt.Errorf("failed to send POST request to host: %w", err) } + // Create a TAP interface. tap, err := water.New(water.Config{ DeviceType: water.TAP, PlatformSpecificParams: water.PlatformSpecificParams{ - Name: iface, + Name: iface, + MultiQueue: true, }, }) if err != nil { - return errors.Wrap(err, "cannot create tap device") + return fmt.Errorf("failed to create tap device: %w", err) } defer tap.Close() + // Set up networking links. if err := linkUp(); err != nil { - return errors.Wrap(err, "cannot set mac address") + return fmt.Errorf("failed to set MAC address: %w", err) } + // Spawn goroutines that forward traffic and obtain a DHCP lease. errCh := make(chan error, 1) go tx(conn, tap, errCh, mtu) go rx(conn, tap, errCh, mtu) go func() { if err := dhcp(); err != nil { - errCh <- errors.Wrap(err, "dhcp error") + errCh <- fmt.Errorf("failed to run DHCP: %w", err) } }() return <-errCh @@ -143,69 +121,60 @@ func dhcp() error { } func rx(conn net.Conn, tap *water.Interface, errCh chan error, mtu int) { - log.Info("waiting for packets...") + elog.Println("Waiting for frames from enclave application.") var frame ethernet.Frame for { frame.Resize(mtu) n, err := tap.Read([]byte(frame)) if err != nil { - errCh <- errors.Wrap(err, "cannot read packet from tap") + errCh <- fmt.Errorf("failed to read packet from TAP device: %w", err) return } frame = frame[:n] - if debug { - packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default) - log.Info(packet.String()) - } - size := make([]byte, 2) binary.LittleEndian.PutUint16(size, uint16(n)) if _, err := conn.Write(size); err != nil { - errCh <- errors.Wrap(err, "cannot write size to socket") + errCh <- fmt.Errorf("failed to write frame size to connection: %w", err) return } if _, err := conn.Write(frame); err != nil { - errCh <- errors.Wrap(err, "cannot write packet to socket") + errCh <- fmt.Errorf("failed to write frame to connection: %w", err) return } } } func tx(conn net.Conn, tap *water.Interface, errCh chan error, mtu int) { + elog.Println("Waiting for frames from host.") sizeBuf := make([]byte, 2) buf := make([]byte, mtu+header.EthernetMinimumSize) for { n, err := io.ReadFull(conn, sizeBuf) if err != nil { - errCh <- errors.Wrap(err, "cannot read size from socket") + errCh <- fmt.Errorf("failed to read frame size from connection: %w", err) return } if n != 2 { - errCh <- fmt.Errorf("unexpected size %d", n) + errCh <- fmt.Errorf("received unexpected frame size %d", n) return } size := int(binary.LittleEndian.Uint16(sizeBuf[0:2])) n, err = io.ReadFull(conn, buf[:size]) if err != nil { - errCh <- errors.Wrap(err, "cannot read payload from socket") + errCh <- fmt.Errorf("failed to read frame from connection: %w", err) return } if n == 0 || n != size { - errCh <- fmt.Errorf("unexpected size %d != %d", n, size) + errCh <- fmt.Errorf("expected frame of size %d but got %d", size, n) return } - if debug { - packet := gopacket.NewPacket(buf[:size], layers.LayerTypeEthernet, gopacket.Default) - log.Info(packet.String()) - } - if _, err := tap.Write(buf[:size]); err != nil { - errCh <- errors.Wrap(err, "cannot write packet to tap") + errCh <- fmt.Errorf("failed to write frame to TAP device: %w", err) return } } diff --git a/system_darwin.go b/system_darwin.go deleted file mode 100644 index 2c15d9a..0000000 --- a/system_darwin.go +++ /dev/null @@ -1,3 +0,0 @@ -package nitriding - -func assignLoAddr() error { return nil } diff --git a/system_linux.go b/system_linux.go deleted file mode 100644 index dfbe498..0000000 --- a/system_linux.go +++ /dev/null @@ -1,27 +0,0 @@ -package nitriding - -import ( - "net" - - "github.com/milosgajdos/tenus" -) - -// assignLoAddr assigns an IP address to the loopback interface, which is -// necessary because Nitro enclaves don't do that out-of-the-box. We need the -// loopback interface because we run a simple TCP proxy that listens on -// 127.0.0.1:1080 and converts AF_INET to AF_VSOCK. -func assignLoAddr() error { - addrStr := "127.0.0.1/8" - l, err := tenus.NewLinkFrom("lo") - if err != nil { - return err - } - addr, network, err := net.ParseCIDR(addrStr) - if err != nil { - return err - } - if err = l.SetLinkIp(addr, network); err != nil { - return err - } - return l.SetLinkUp() -} From 167c5cf1a23e78367d0e75dc24d727dfbe66e692 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 24 Oct 2022 16:58:51 -0500 Subject: [PATCH 11/55] Remove AddRoute. Nitriding is now a stand-alone application, obviating the need for an API to add HTTP handlers. --- enclave.go | 25 ------------------------- enclave_test.go | 31 ------------------------------- 2 files changed, 56 deletions(-) diff --git a/enclave.go b/enclave.go index 2a1db14..1db86f7 100644 --- a/enclave.go +++ b/enclave.go @@ -369,31 +369,6 @@ func (e *Enclave) setCertFingerprint(rawData []byte) error { return nil } -// AddRoute adds an HTTP handler for the given HTTP method and pattern. -func (e *Enclave) AddRoute(method, pattern string, handlerFn http.HandlerFunc) { - r := e.pubSrv.Handler.(*chi.Mux) - switch method { - case http.MethodGet: - r.Get(pattern, handlerFn) - case http.MethodHead: - r.Head(pattern, handlerFn) - case http.MethodPost: - r.Post(pattern, handlerFn) - case http.MethodPut: - r.Put(pattern, handlerFn) - case http.MethodPatch: - r.Patch(pattern, handlerFn) - case http.MethodDelete: - r.Delete(pattern, handlerFn) - case http.MethodConnect: - r.Connect(pattern, handlerFn) - case http.MethodOptions: - r.Options(pattern, handlerFn) - case http.MethodTrace: - r.Trace(pattern, handlerFn) - } -} - // SetKeyMaterial registers the enclave's key material (e.g., secret encryption // keys) as being ready to be synchronized to other, identical enclaves. Note // that the key material's underlying data structure must be marshallable to diff --git a/enclave_test.go b/enclave_test.go index 49b46fc..8edb03a 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -2,10 +2,6 @@ package nitriding import ( "errors" - "fmt" - "io" - "net/http" - "net/http/httptest" "testing" ) @@ -53,33 +49,6 @@ func TestGenSelfSignedCert(t *testing.T) { } } -func TestAddRoute(t *testing.T) { - pathFoo := "/foo" - expectedBody := "foo" - handler := func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, expectedBody) - } - - e := createEnclave() - e.AddRoute(http.MethodGet, pathFoo, handler) - - req := httptest.NewRequest(http.MethodGet, pathFoo, nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, err := io.ReadAll(resp.Body) - if err != nil { - t.Fatalf("Failed to read response body: %s", err) - } - if string(body) != expectedBody { - t.Fatalf("Expected body %q but got %q.", expectedBody, string(body)) - } - if resp.StatusCode != http.StatusOK { - t.Fatalf("Expected status code %d but got %d.", http.StatusOK, resp.StatusCode) - } -} - func TestKeyMaterial(t *testing.T) { e := createEnclave() k := struct{ Foo string }{"foobar"} From 3f19c828db9f0c6a2c823e69dd2aebfbe00306b7 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 25 Oct 2022 09:36:47 -0500 Subject: [PATCH 12/55] Re-create networking if necessary. --- enclave.go | 6 ++---- proxy.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/enclave.go b/enclave.go index 1db86f7..860430d 100644 --- a/enclave.go +++ b/enclave.go @@ -159,7 +159,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { m.Get(pathRoot, getIndexHandler(e.cfg)) // Register enclave-internal HTTP API. m = e.privSrv.Handler.(*chi.Mux) - m.Put(pathPostKeys, getRegisterKeysHandler(e)) + m.Put(pathPostKeys, getSetKeysHandler(e)) if cfg.Debug { e.pubSrv.Handler.(*chi.Mux).Use(middleware.Logger) @@ -183,9 +183,7 @@ func (e *Enclave) Start() error { // Set up our networking environment which creates a TAP device that // forwards traffic (via the VSOCK interface) to the EC2 host. - if err = setupNetworking(e.cfg); err != nil { - return fmt.Errorf("%s: failed to set up proxying: %w", errPrefix, err) - } + go runNetworking(e.cfg) // Get an HTTPS certificate. if e.cfg.UseACME { diff --git a/proxy.go b/proxy.go index 7c5bd74..7106d92 100644 --- a/proxy.go +++ b/proxy.go @@ -11,6 +11,7 @@ import ( "net/http" "os" "os/exec" + "time" "github.com/containers/gvisor-tap-vsock/pkg/transport" "github.com/songgao/packets/ethernet" @@ -30,6 +31,17 @@ const ( mac = "5a:94:ef:e4:0c:ee" ) +// runNetworking calls the function that sets up our networking environment. +// If anything fails, we try again after a brief wait period. +func runNetworking(c *Config) { + for { + if err := setupNetworking(c); err != nil { + elog.Printf("TAP tunnel to EC2 host failed: %v. Restarting.", err) + } + time.Sleep(time.Second) + } +} + // setupNetworking sets up the enclave's networking environment. In // particular, this function: // From a2020811675faa4dd06823dcab3937114b098d45 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 25 Oct 2022 09:39:55 -0500 Subject: [PATCH 13/55] Rename handler. --- handlers.go | 4 ++-- handlers_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/handlers.go b/handlers.go index 32c75b2..797b1d1 100644 --- a/handlers.go +++ b/handlers.go @@ -35,10 +35,10 @@ func getIndexHandler(cfg *Config) http.HandlerFunc { } } -// getRegisterKeysHandler returns a handler that lets the enclave application +// getSetKeysHandler returns a handler that lets the enclave application // register its key material with nitriding. The key material can be arbitrary // bytes. -func getRegisterKeysHandler(e *Enclave) http.HandlerFunc { +func getSetKeysHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(newLimitReader(r.Body, maxKeyMaterialLen)) if err != nil { diff --git a/handlers_test.go b/handlers_test.go index b3d54e9..e1bafc9 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -10,7 +10,7 @@ import ( func TestGetRegisterKeysHandler(t *testing.T) { expected := []byte{1, 2, 3, 4, 5} // The key material that we're setting and retrieving. e := createEnclave() - handler := getRegisterKeysHandler(e) + handler := getSetKeysHandler(e) rec := httptest.NewRecorder() req, err := http.NewRequest(http.MethodPut, pathPostKeys, bytes.NewReader(expected)) if err != nil { From 52ad0d690764cbc367b696a69afe92f9a817f91f Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 25 Oct 2022 09:59:29 -0500 Subject: [PATCH 14/55] Display domain socket address. --- enclave.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enclave.go b/enclave.go index 860430d..fd3ca92 100644 --- a/enclave.go +++ b/enclave.go @@ -205,7 +205,7 @@ func (e *Enclave) Start() error { // startWebServers starts both our public-facing and our enclave-internal Web // server in a goroutine. func startWebServers(e *Enclave) error { - elog.Printf("Starting public (%s) and private (%s) Web server.", e.pubSrv.Addr, e.privSrv.Addr) + elog.Printf("Starting public (%s) and private (%s) Web server.", e.pubSrv.Addr, e.cfg.SockAddr) l, err := createUnixSocket(e.cfg.SockAddr) if err != nil { From ea0971fe8be0d44bb71921ac3d099a80548357de Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 25 Oct 2022 10:04:21 -0500 Subject: [PATCH 15/55] Add log messages. --- proxy.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proxy.go b/proxy.go index 7106d92..f645604 100644 --- a/proxy.go +++ b/proxy.go @@ -62,6 +62,7 @@ func setupNetworking(c *Config) error { return fmt.Errorf("failed to connect to host: %w", err) } defer conn.Close() + elog.Println("Established connection with EC2 host.") req, err := http.NewRequest(http.MethodPost, path, nil) if err != nil { @@ -70,6 +71,7 @@ func setupNetworking(c *Config) error { if err := req.Write(conn); err != nil { return fmt.Errorf("failed to send POST request to host: %w", err) } + elog.Println("Sent HTTP request to EC2 host.") // Create a TAP interface. tap, err := water.New(water.Config{ @@ -83,11 +85,13 @@ func setupNetworking(c *Config) error { return fmt.Errorf("failed to create tap device: %w", err) } defer tap.Close() + elog.Println("Created TAP device.") // Set up networking links. if err := linkUp(); err != nil { return fmt.Errorf("failed to set MAC address: %w", err) } + elog.Println("Created networking link.") // Spawn goroutines that forward traffic and obtain a DHCP lease. errCh := make(chan error, 1) @@ -98,6 +102,7 @@ func setupNetworking(c *Config) error { errCh <- fmt.Errorf("failed to run DHCP: %w", err) } }() + elog.Println("Started goroutines to forward traffic.") return <-errCh } From 34614867de8254396d7d97752d5c85a56880c5a6 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Wed, 26 Oct 2022 08:23:03 -0500 Subject: [PATCH 16/55] Rename handlers and add tests. --- enclave.go | 7 +++---- handlers.go | 34 +++++++++++++++++++++++++++++----- handlers_test.go | 32 ++++++++++++++++++++++---------- keysync_initiator.go | 2 +- keysync_responder_test.go | 8 ++++---- 5 files changed, 59 insertions(+), 24 deletions(-) diff --git a/enclave.go b/enclave.go index fd3ca92..5e44564 100644 --- a/enclave.go +++ b/enclave.go @@ -38,8 +38,7 @@ const ( parentCID = 3 pathNonce = "/nonce" pathAttestation = "/attestation" - pathGetKeys = "/get-keys" - pathPostKeys = "/post-keys" + pathState = "/state" pathRoot = "/" ) @@ -155,11 +154,11 @@ func NewEnclave(cfg *Config) (*Enclave, error) { m := e.pubSrv.Handler.(*chi.Mux) m.Get(pathAttestation, getAttestationHandler(&e.certFpr)) m.Get(pathNonce, getNonceHandler(e)) - m.Get(pathGetKeys, getKeysHandler(e, time.Now)) + m.Get(pathState, getStateHandler(e)) m.Get(pathRoot, getIndexHandler(e.cfg)) // Register enclave-internal HTTP API. m = e.privSrv.Handler.(*chi.Mux) - m.Put(pathPostKeys, getSetKeysHandler(e)) + m.Put(pathState, setStateHandler(e)) if cfg.Debug { e.pubSrv.Handler.(*chi.Mux).Use(middleware.Logger) diff --git a/handlers.go b/handlers.go index 797b1d1..403523e 100644 --- a/handlers.go +++ b/handlers.go @@ -14,7 +14,8 @@ const ( ) var ( - errFailedReqBody = errors.New("failed to read request body") + errFailedReqBody = errors.New("failed to read request body") + errFailedGetState = errors.New("failed to retrieve saved state") ) func formatIndexPage(appURL string) string { @@ -35,10 +36,33 @@ func getIndexHandler(cfg *Config) http.HandlerFunc { } } -// getSetKeysHandler returns a handler that lets the enclave application -// register its key material with nitriding. The key material can be arbitrary -// bytes. -func getSetKeysHandler(e *Enclave) http.HandlerFunc { +// getStateHandler returns a handler that lets the enclave application retrieve +// previously-set state. +func getStateHandler(e *Enclave) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/octet-stream") + s, err := e.KeyMaterial() + if err != nil { + http.Error(w, errFailedGetState.Error(), http.StatusInternalServerError) + return + } + n, err := w.Write(s.([]byte)) + if err != nil { + elog.Printf("Error writing state to client: %v", err) + return + } + expected := len(s.([]byte)) + if n != expected { + elog.Printf("Only wrote %d out of %d-byte state to client.", n, expected) + return + } + } +} + +// setStateHandler returns a handler that lets the enclave application set +// state that's synchronized with another enclave in case of horizontal +// scaling. The state can be arbitrary bytes. +func setStateHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(newLimitReader(r.Body, maxKeyMaterialLen)) if err != nil { diff --git a/handlers_test.go b/handlers_test.go index e1bafc9..bea5f56 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -2,22 +2,24 @@ package nitriding import ( "bytes" + "io" "net/http" "net/http/httptest" "testing" ) -func TestGetRegisterKeysHandler(t *testing.T) { +func TestStateHandlers(t *testing.T) { expected := []byte{1, 2, 3, 4, 5} // The key material that we're setting and retrieving. e := createEnclave() - handler := getSetKeysHandler(e) + setHandler := setStateHandler(e) + getHandler := getStateHandler(e) rec := httptest.NewRecorder() - req, err := http.NewRequest(http.MethodPut, pathPostKeys, bytes.NewReader(expected)) + req, err := http.NewRequest(http.MethodPut, pathState, bytes.NewReader(expected)) if err != nil { t.Fatalf("Failed to create HTTP request: %v", err) } - handler(rec, req) + setHandler(rec, req) resp := rec.Result() // As long as we don't hit our (generous) upload limit, we always expect an @@ -26,14 +28,24 @@ func TestGetRegisterKeysHandler(t *testing.T) { t.Fatalf("Expected HTTP status code %d but got %d.", http.StatusOK, resp.StatusCode) } - // Make sure that the key material was set in the enclave. - m, err := e.KeyMaterial() + // Now retrieve the state and make sure that it's what we sent earlier. + req, err = http.NewRequest(http.MethodGet, pathState, nil) if err != nil { - t.Fatalf("Failed to obtain enclave key material: %v", err) + t.Fatalf("Failed to create HTTP request: %v", err) } - retrieved := m.([]byte) + rec = httptest.NewRecorder() + getHandler(rec, req) + resp = rec.Result() - if !bytes.Equal(retrieved, expected) { - t.Fatalf("Expected %q but got %q.", expected, retrieved) + if resp.StatusCode != http.StatusOK { + t.Fatalf("Expected HTTP status code %d but got %d.", http.StatusOK, resp.StatusCode) + } + + retrieved, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatalf("Failed to read HTTP response body: %v", err) + } + if !bytes.Equal(expected, retrieved) { + t.Fatalf("Expected state %q but got %q.", expected, retrieved) } } diff --git a/keysync_initiator.go b/keysync_initiator.go index e684878..46b5f4d 100644 --- a/keysync_initiator.go +++ b/keysync_initiator.go @@ -125,7 +125,7 @@ func requestNonce(addr string) (nonce, error) { func requestAttDoc(addr string, ourAttDoc []byte) ([]byte, error) { errStr := "failed to fetch attestation doc from remote enclave" - endpoint := fmt.Sprintf("%s%s", addr, pathGetKeys) + endpoint := fmt.Sprintf("%s%s", addr, pathState) // Finally, send our attestation document to the remote enclave. If // everything works out, the remote enclave is going to respond with its diff --git a/keysync_responder_test.go b/keysync_responder_test.go index ae7c224..46e98fa 100644 --- a/keysync_responder_test.go +++ b/keysync_responder_test.go @@ -77,11 +77,11 @@ func TestKeysHandlerForBadReqs(t *testing.T) { enclave := createEnclave() // Send non-Base64 bogus data. - res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, strings.NewReader("foobar!")) + res = queryHandler(getKeysHandler(enclave, time.Now), pathState, strings.NewReader("foobar!")) expect(t, res, http.StatusInternalServerError, errNoBase64.Error()) // Send Base64-encoded bogus data. - res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, strings.NewReader("Zm9vYmFyCg==")) + res = queryHandler(getKeysHandler(enclave, time.Now), pathState, strings.NewReader("Zm9vYmFyCg==")) expect(t, res, http.StatusUnauthorized, errFailedVerify.Error()) } @@ -96,7 +96,7 @@ func TestKeysHandler(t *testing.T) { } currentTime = func() time.Time { return initAttInfo.attDocTime } - res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, strings.NewReader(initAttInfo.attDoc)) + res = queryHandler(getKeysHandler(enclave, time.Now), pathState, strings.NewReader(initAttInfo.attDoc)) // On a non-enclave platform, the responder code will get as far as to // request its attestation document. expect(t, res, http.StatusInternalServerError, errFailedAttestation) @@ -109,7 +109,7 @@ func TestKeysHandlerDoS(t *testing.T) { // Send more data than the handler should be willing to read. maxSize := base64.StdEncoding.EncodedLen(maxAttDocLen) body := make([]byte, maxSize+1) - res = queryHandler(getKeysHandler(enclave, time.Now), pathGetKeys, bytes.NewReader(body)) + res = queryHandler(getKeysHandler(enclave, time.Now), pathState, bytes.NewReader(body)) expect(t, res, http.StatusInternalServerError, errFailedRespBody.Error()) } From cf0284c2bb34f95fce1d0f856fae502d1ad8857f Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 27 Oct 2022 08:36:54 -0500 Subject: [PATCH 17/55] Add sync handler. --- enclave.go | 2 ++ handlers.go | 31 +++++++++++++++++++++++++++++++ handlers_test.go | 14 ++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/enclave.go b/enclave.go index 5e44564..81968d2 100644 --- a/enclave.go +++ b/enclave.go @@ -39,6 +39,7 @@ const ( pathNonce = "/nonce" pathAttestation = "/attestation" pathState = "/state" + pathSync = "/sync" pathRoot = "/" ) @@ -155,6 +156,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { m.Get(pathAttestation, getAttestationHandler(&e.certFpr)) m.Get(pathNonce, getNonceHandler(e)) m.Get(pathState, getStateHandler(e)) + m.Get(pathSync, syncHandler(e)) m.Get(pathRoot, getIndexHandler(e.cfg)) // Register enclave-internal HTTP API. m = e.privSrv.Handler.(*chi.Mux) diff --git a/handlers.go b/handlers.go index 403523e..dce0b4b 100644 --- a/handlers.go +++ b/handlers.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net/http" + "net/url" ) const ( @@ -16,6 +17,7 @@ const ( var ( errFailedReqBody = errors.New("failed to read request body") errFailedGetState = errors.New("failed to retrieve saved state") + errNoAddr = errors.New("parameter 'addr' not found") ) func formatIndexPage(appURL string) string { @@ -36,6 +38,35 @@ func getIndexHandler(cfg *Config) http.HandlerFunc { } } +// syncHandler returns a handler that lets the enclave application trigger +// state synchronization, which copies the given remote enclave's state into +// our state. +func syncHandler(e *Enclave) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + q := r.URL.Query() + // The 'addr' parameter must have the following form: + // https://example.com:8443 + addrs, ok := q["addr"] + if !ok { + http.Error(w, errNoAddr.Error(), http.StatusBadRequest) + return + } + addr := addrs[0] + + // Are we dealing with a well-formed URL? + if _, err := url.Parse(addr); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + if err := RequestKeys(addr, e.KeyMaterial); err != nil { + http.Error(w, fmt.Sprintf("failed to synchronize state: %v", err), http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + } +} + // getStateHandler returns a handler that lets the enclave application retrieve // previously-set state. func getStateHandler(e *Enclave) http.HandlerFunc { diff --git a/handlers_test.go b/handlers_test.go index bea5f56..6032b5c 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -8,6 +8,20 @@ import ( "testing" ) +func TestSyncHandler(t *testing.T) { + e := createEnclave() + h := syncHandler(e) + rec := httptest.NewRecorder() + + req, err := http.NewRequest(http.MethodGet, pathSync, nil) + if err != nil { + t.Fatalf("Failed to create HTTP request: %v", err) + } + h(rec, req) + + expect(t, rec.Result(), http.StatusBadRequest, errNoAddr.Error()) +} + func TestStateHandlers(t *testing.T) { expected := []byte{1, 2, 3, 4, 5} // The key material that we're setting and retrieving. e := createEnclave() From f60dcf273a9cbbe219156ea81a15515fbdf19729 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 27 Oct 2022 13:05:06 -0500 Subject: [PATCH 18/55] Update comment. --- enclave.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/enclave.go b/enclave.go index 81968d2..d6a4a5c 100644 --- a/enclave.go +++ b/enclave.go @@ -170,9 +170,8 @@ func NewEnclave(cfg *Config) (*Enclave, error) { return e, nil } -// Start starts the Nitro Enclave. If it bootstraps correctly, this function -// won't return because it starts an HTTPS server. If something goes wrong, -// the function returns an error. +// Start starts the Nitro Enclave. If something goes wrong, the function +// returns an error. func (e *Enclave) Start() error { var err error errPrefix := "failed to start Nitro Enclave" From 894f70107a63f5fc2d0231837ce2fcbbf2ea7a1a Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 14 Nov 2022 11:36:30 -0600 Subject: [PATCH 19/55] Block forever after starting the enclave. --- cmd/main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index 3c8191e..3d87fc7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -37,8 +37,10 @@ func main() { l.Fatalf("Failed to create enclave: %v", err) } - // Start blocks for as long as the enclave is alive. if err := enclave.Start(); err != nil { l.Fatalf("Enclave terminated: %v", err) } + + // Block on this read forever. + <-make(chan struct{}) } From 02da09e8bae9afc2917234035c08c6648a60f7b7 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 14 Nov 2022 11:37:13 -0600 Subject: [PATCH 20/55] Add Go dependencies of command line tool. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 716f8f0..5c4a486 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ binary = cmd/nitriding godeps = *.go go.mod go.sum +cmddeps = cmd/*.go all: test lint $(binary) @@ -11,7 +12,7 @@ lint: test: $(godeps) @go test -cover ./... -$(binary): $(godeps) +$(binary): $(godeps) $(cmddeps) make -C cmd/ clean: From a120b7ce3a7f26b086649c09f4f3e6cc46eb2d27 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 14 Nov 2022 15:46:08 -0600 Subject: [PATCH 21/55] Add reverse proxy for enclave application. The reverse proxy terminates TLS and forwards all but a select few HTTP requests to the enclave application, which runs its own Web server. Since the reverse proxy terminates TLS, the enclave application does not need to bother with certificates and can expose a simple HTTP server. --- cmd/main.go | 37 +++++++++++++++++++++++++++++------- enclave.go | 45 ++++++++++++++++++++++++++++++++++---------- enclave_test.go | 19 ++++++++++--------- handlers.go | 12 +++++++++++- handlers_test.go | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 27 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 3d87fc7..aa44c09 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "log" + "net/url" "os" "github.com/brave/nitriding" @@ -11,18 +12,39 @@ import ( var l = log.New(os.Stderr, "nitriding-cmd: ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile) func main() { - var sockAddr, fqdn, appURL string + var sockAddr, fqdn, appURL, appWebSrv string var port, hostProxyPort int var useACME bool + var u *url.URL + var err error - flag.StringVar(&fqdn, "fqdn", "example.com", "FQDN for the enclave application.") - flag.StringVar(&sockAddr, "sockaddr", "/tmp/nitriding.sock", "Path to unix domain socket for enclave-internal IPC.") - flag.StringVar(&appURL, "appurl", "github.com/foo/bar", "Code repository for the enclave application.") - flag.IntVar(&port, "port", 8443, "Nitriding's VSOCK-facing HTTP port. Must match port forwarding rules on EC2 host.") - flag.IntVar(&hostProxyPort, "host-proxy-port", 1024, "Port of proxy application running on EC2 host.") - flag.BoolVar(&useACME, "acme", true, "Use Let's Encrypt's ACME to fetch HTTPS certificate.") + flag.StringVar(&fqdn, "fqdn", "", + "FQDN of the enclave application (e.g., \"example.com\").") + flag.StringVar(&sockAddr, "sockaddr", "/tmp/nitriding.sock", + "Path to Unix domain socket for enclave-internal IPC.") + flag.StringVar(&appURL, "appurl", "", + "Code repository of the enclave application (e.g., \"github.com/foo/bar\").") + flag.StringVar(&appWebSrv, "appwebsrv", "", + "Enclave-internal HTTP server of the enclave application (e.g., \"http://127.0.0.1:8080\").") + flag.IntVar(&port, "port", 8443, + "Nitriding's VSOCK-facing HTTPS port. Must match port forwarding rules on EC2 host.") + flag.IntVar(&hostProxyPort, "host-proxy-port", 1024, + "Port of proxy application running on EC2 host.") + flag.BoolVar(&useACME, "acme", false, + "Use Let's Encrypt's ACME to fetch HTTPS certificate.") flag.Parse() + if useACME && fqdn == "" { + l.Fatalf("Fully qualified domain name not given. Use the -fqdn flag.") + } + + if appWebSrv != "" { + u, err = url.Parse(appWebSrv) + if err != nil { + l.Fatalf("Failed to parse URL of Web server: %v", err) + } + } + enclave, err := nitriding.NewEnclave( &nitriding.Config{ FQDN: fqdn, @@ -31,6 +53,7 @@ func main() { UseACME: useACME, SockAddr: sockAddr, AppURL: appURL, + AppWebSrv: u, }, ) if err != nil { diff --git a/enclave.go b/enclave.go index d6a4a5c..49708b5 100644 --- a/enclave.go +++ b/enclave.go @@ -17,6 +17,8 @@ import ( "log" "math/big" "net/http" + "net/http/httputil" + "net/url" "os" "sync" "time" @@ -35,12 +37,16 @@ const ( // parentCID determines the CID (analogous to an IP address) of the parent // EC2 instance. According to the AWS docs, it is always 3: // https://docs.aws.amazon.com/enclaves/latest/user/nitro-enclave-concepts.html - parentCID = 3 - pathNonce = "/nonce" - pathAttestation = "/attestation" - pathState = "/state" - pathSync = "/sync" - pathRoot = "/" + parentCID = 3 + // The following paths are handled by nitriding. + pathRoot = "/enclave" + pathNonce = "/enclave/nonce" + pathAttestation = "/enclave/attestation" + pathState = "/enclave/state" + pathSync = "/enclave/sync" + // All other paths are handled by the enclave application's Web server if + // it exists. + pathProxy = "/*" ) var ( @@ -56,6 +62,7 @@ type Enclave struct { sync.RWMutex cfg *Config pubSrv, privSrv http.Server + revProxy *httputil.ReverseProxy certFpr [sha256.Size]byte nonceCache *cache keyMaterial any @@ -108,6 +115,14 @@ type Config struct { // is shown on the enclave's index page, as part of instructions on how to // do remote attestation. AppURL string + + // AppWebSrv should be set to the enclave-internal Web server of the + // enclave application, e.g., "http://127.0.0.1:8080". Nitriding acts as a + // TLS-terminating reverse proxy and forwards incoming HTTP requests to + // this Web server. Note that this configuration option is only necessary + // if the enclave application exposes an HTTP server. Non-HTTP enclave + // applications can ignore this. + AppWebSrv *url.URL } // Validate returns an error if required fields in the config are not set. @@ -151,17 +166,25 @@ func NewEnclave(cfg *Config) (*Enclave, error) { }, nonceCache: newCache(defaultItemExpiry), } + // Register public HTTP API. m := e.pubSrv.Handler.(*chi.Mux) m.Get(pathAttestation, getAttestationHandler(&e.certFpr)) m.Get(pathNonce, getNonceHandler(e)) - m.Get(pathState, getStateHandler(e)) - m.Get(pathSync, syncHandler(e)) m.Get(pathRoot, getIndexHandler(e.cfg)) // Register enclave-internal HTTP API. m = e.privSrv.Handler.(*chi.Mux) + m.Get(pathSync, syncHandler(e)) + m.Get(pathState, getStateHandler(e)) m.Put(pathState, setStateHandler(e)) + // Configure our reverse proxy if the enclave application exposes an HTTP + // server. + if cfg.AppWebSrv != nil { + e.revProxy = httputil.NewSingleHostReverseProxy(cfg.AppWebSrv) + e.pubSrv.Handler.(*chi.Mux).Handle(pathProxy, proxyHandler(e)) + } + if cfg.Debug { e.pubSrv.Handler.(*chi.Mux).Use(middleware.Logger) e.privSrv.Handler.(*chi.Mux).Use(middleware.Logger) @@ -177,8 +200,10 @@ func (e *Enclave) Start() error { errPrefix := "failed to start Nitro Enclave" // Set file descriptor limit. There's no need to exit if this fails. - if err = setFdLimit(e.cfg.FdCur, e.cfg.FdMax); err != nil { - elog.Printf("Failed to set new file descriptor limit: %s", err) + if inEnclave { + if err = setFdLimit(e.cfg.FdCur, e.cfg.FdMax); err != nil { + elog.Printf("Failed to set new file descriptor limit: %s", err) + } } // Set up our networking environment which creates a TAP device that diff --git a/enclave_test.go b/enclave_test.go index 8edb03a..9adf595 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -5,16 +5,17 @@ import ( "testing" ) +var defaultCfg = &Config{ + FQDN: "example.com", + Port: 50000, + UseACME: false, + Debug: false, + FdCur: 1024, + FdMax: 4096, +} + func createEnclave() *Enclave { - cfg := &Config{ - FQDN: "example.com", - Port: 50000, - UseACME: false, - Debug: false, - FdCur: 1024, - FdMax: 4096, - } - e, err := NewEnclave(cfg) + e, err := NewEnclave(defaultCfg) if err != nil { panic(err) } diff --git a/handlers.go b/handlers.go index dce0b4b..8967b72 100644 --- a/handlers.go +++ b/handlers.go @@ -12,6 +12,8 @@ const ( // The maximum length of the key material (in bytes) that enclave // applications can PUT to our HTTP API. maxKeyMaterialLen = 1024 * 1024 + // The HTML for the enclave's index page. + indexPage = "This host runs inside an AWS Nitro Enclave.\n" ) var ( @@ -21,7 +23,7 @@ var ( ) func formatIndexPage(appURL string) string { - page := "This host runs inside an AWS Nitro Enclave.\n" + page := indexPage if appURL != "" { page += fmt.Sprintf("\nIt runs the following code: %s\n"+ "Use the following tool to verify the enclave: "+ @@ -104,3 +106,11 @@ func setStateHandler(e *Enclave) http.HandlerFunc { w.WriteHeader(http.StatusOK) } } + +// proxyHandler returns an HTTP handler that proxies HTTP requests to the +// enclave-internal HTTP server of our enclave application. +func proxyHandler(e *Enclave) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + e.revProxy.ServeHTTP(w, r) + } +} diff --git a/handlers_test.go b/handlers_test.go index 6032b5c..c5eec6e 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -2,9 +2,13 @@ package nitriding import ( "bytes" + "crypto/tls" + "fmt" "io" "net/http" "net/http/httptest" + "net/http/httputil" + "net/url" "testing" ) @@ -63,3 +67,48 @@ func TestStateHandlers(t *testing.T) { t.Fatalf("Expected state %q but got %q.", expected, retrieved) } } + +func TestProxyHandler(t *testing.T) { + appPage := "foobar" + + // Nitring acts as a reverse proxy to this Web server. + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, appPage) + })) + defer srv.Close() + u, err := url.Parse(srv.URL) + if err != nil { + t.Fatal(err) + } + + c := defaultCfg + c.AppWebSrv = u + e, err := NewEnclave(c) + if err != nil { + t.Fatal(err) + } + e.revProxy = httputil.NewSingleHostReverseProxy(u) + if err := e.Start(); err != nil { + t.Fatal(err) + } + + // Skip certificate validation because we are using a self-signed + // certificate in this test. + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + nitridingSrv := "https://127.0.0.1" + e.pubSrv.Addr + + // Request the enclave's index page. Nitriding is going to return it. + resp, err := http.Get(nitridingSrv + pathRoot) + if err != nil { + t.Fatal(err) + } + expect(t, resp, http.StatusOK, indexPage) + + // Request a random page. Nitriding is going to forwrad the request to our + // test Web server. + resp, err = http.Get(nitridingSrv + "/foo/bar") + if err != nil { + t.Fatal(err) + } + expect(t, resp, http.StatusOK, appPage) +} From 00f40b8bdeae5fa5e2af6f35467797e436450a5b Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 15 Nov 2022 09:42:06 -0600 Subject: [PATCH 22/55] Provide a function to shut down the enclave. --- enclave.go | 19 ++++++++++++++++++- enclave_test.go | 13 +++++++------ handlers_test.go | 1 + proxy.go | 18 +++++++++++++----- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/enclave.go b/enclave.go index 49708b5..dc8eda7 100644 --- a/enclave.go +++ b/enclave.go @@ -66,6 +66,7 @@ type Enclave struct { certFpr [sha256.Size]byte nonceCache *cache keyMaterial any + stop chan bool } // Config represents the configuration of our enclave service. @@ -165,6 +166,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { Handler: chi.NewRouter(), }, nonceCache: newCache(defaultItemExpiry), + stop: make(chan bool), } // Register public HTTP API. @@ -208,7 +210,7 @@ func (e *Enclave) Start() error { // Set up our networking environment which creates a TAP device that // forwards traffic (via the VSOCK interface) to the EC2 host. - go runNetworking(e.cfg) + go runNetworking(e.cfg, e.stop) // Get an HTTPS certificate. if e.cfg.UseACME { @@ -227,6 +229,21 @@ func (e *Enclave) Start() error { return nil } +// Stop stops the enclave. +func (e *Enclave) Stop() error { + close(e.stop) + if err := e.privSrv.Shutdown(context.Background()); err != nil { + return err + } + if err := e.pubSrv.Shutdown(context.Background()); err != nil { + return err + } + if err := os.RemoveAll(e.cfg.SockAddr); err != nil { + return err + } + return nil +} + // startWebServers starts both our public-facing and our enclave-internal Web // server in a goroutine. func startWebServers(e *Enclave) error { diff --git a/enclave_test.go b/enclave_test.go index 9adf595..56d286d 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -6,12 +6,13 @@ import ( ) var defaultCfg = &Config{ - FQDN: "example.com", - Port: 50000, - UseACME: false, - Debug: false, - FdCur: 1024, - FdMax: 4096, + FQDN: "example.com", + SockAddr: "/tmp/nitriding.sock", + Port: 50000, + UseACME: false, + Debug: false, + FdCur: 1024, + FdMax: 4096, } func createEnclave() *Enclave { diff --git a/handlers_test.go b/handlers_test.go index c5eec6e..5a10ece 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -91,6 +91,7 @@ func TestProxyHandler(t *testing.T) { if err := e.Start(); err != nil { t.Fatal(err) } + defer e.Stop() //nolint:errcheck // Skip certificate validation because we are using a self-signed // certificate in this test. diff --git a/proxy.go b/proxy.go index f645604..f91475e 100644 --- a/proxy.go +++ b/proxy.go @@ -33,11 +33,13 @@ const ( // runNetworking calls the function that sets up our networking environment. // If anything fails, we try again after a brief wait period. -func runNetworking(c *Config) { +func runNetworking(c *Config, stop chan bool) { + var err error for { - if err := setupNetworking(c); err != nil { - elog.Printf("TAP tunnel to EC2 host failed: %v. Restarting.", err) + if err = setupNetworking(c, stop); err == nil { + return } + elog.Printf("TAP tunnel to EC2 host failed: %v. Restarting.", err) time.Sleep(time.Second) } } @@ -51,7 +53,7 @@ func runNetworking(c *Config) { // 4. Run DHCP to obtain an IP address. // 5. Spawn goroutines to forward traffic between the TAP device and the proxy // running on the host. -func setupNetworking(c *Config) error { +func setupNetworking(c *Config, stop chan bool) error { elog.Println("Setting up networking between host and enclave.") defer elog.Println("Tearing down networking between host and enclave.") @@ -103,7 +105,13 @@ func setupNetworking(c *Config) error { } }() elog.Println("Started goroutines to forward traffic.") - return <-errCh + select { + case err := <-errCh: + return err + case <-stop: + elog.Printf("Shutting down networking.") + return nil + } } func linkUp() error { From b3d08c2476f20ec0dd7d5332c1099777243683af Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 15 Nov 2022 11:35:21 -0600 Subject: [PATCH 23/55] Allow application to register key material. Non-HTTP enclave applications need a way to link their key material to the attestation document, which serves as our root of trust. This commit adds a new enclave-internal endpoint that allows applications to register a hash over their public key material. This hash (along with a hash over nitriding's HTTPS certificate) is then embedded in attestation documents. --- attestation.go | 19 +++++++++++++++++-- attestation_test.go | 32 +++++++++++++++++++++++++++++++- enclave.go | 12 ++++++++---- handlers.go | 36 ++++++++++++++++++++++++++++++++++++ handlers_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 7 deletions(-) diff --git a/attestation.go b/attestation.go index db62dd5..b89508a 100644 --- a/attestation.go +++ b/attestation.go @@ -2,6 +2,7 @@ package nitriding import ( "bytes" + "crypto/sha256" "encoding/base64" "encoding/hex" "errors" @@ -34,13 +35,27 @@ var ( getPCRValues = func() (map[uint][]byte, error) { return _getPCRValues() } ) +// AttestationHashes contains hashes over public key material which we embed in +// the enclave's attestation document for clients to verify. +type AttestationHashes struct { + tlsKeyHash [sha256.Size]byte // Always set. + appKeyHash [sha256.Size]byte // Sometimes set, depending on application. +} + +// Serialize returns a byte slice that contains our concatenated hashes. Note +// that all hashes are always present. If a hash was not initialized, it's set +// to 0-bytes. +func (a *AttestationHashes) Serialize() []byte { + return append(a.tlsKeyHash[:], a.appKeyHash[:]...) +} + // getAttestationHandler takes as input a SHA-256 hash over an HTTPS // certificate and returns a HandlerFunc. This HandlerFunc expects a nonce in // the URL query parameters and subsequently asks its hypervisor for an // attestation document that contains both the nonce and the certificate hash. // The resulting Base64-encoded attestation document is then returned to the // requester. -func getAttestationHandler(certHash *[32]byte) http.HandlerFunc { +func getAttestationHandler(hashes *AttestationHashes) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, errMethodNotGET, http.StatusMethodNotAllowed) @@ -67,7 +82,7 @@ func getAttestationHandler(certHash *[32]byte) http.HandlerFunc { return } - rawDoc, err := attest(rawNonce, certHash[:], nil) + rawDoc, err := attest(rawNonce, hashes.Serialize(), nil) if err != nil { http.Error(w, errFailedAttestation, http.StatusInternalServerError) return diff --git a/attestation_test.go b/attestation_test.go index e0c88a4..c370128 100644 --- a/attestation_test.go +++ b/attestation_test.go @@ -1,6 +1,9 @@ package nitriding import ( + "bytes" + "crypto/sha256" + "encoding/base64" "io" "net/http" "net/http/httptest" @@ -31,7 +34,7 @@ func expect(t *testing.T, resp *http.Response, statusCode int, errMsg string) { } func testReq(t *testing.T, req *http.Request, statusCode int, errMsg string) { - attestationHandler := getAttestationHandler(&[32]byte{}) + attestationHandler := getAttestationHandler(&AttestationHashes{}) rec := httptest.NewRecorder() attestationHandler(rec, req) expect(t, rec.Result(), statusCode, errMsg) @@ -84,3 +87,30 @@ func TestArePCRsIdentical(t *testing.T) { t.Fatal("Failed to recognize different PCRs as such.") } } + +func TestAttestationHashes(t *testing.T) { + e := createEnclave() + appKeyHash := [sha256.Size]byte{} + + // Start the enclave. This is going to initialize the hash over the HTTPS + // certificate. + if err := e.Start(); err != nil { + t.Fatal(err) + } + defer e.Stop() //nolint:errcheck + + // Register dummy key material for the other hash to be initialized. + rec := httptest.NewRecorder() + buf := bytes.NewBufferString(base64.StdEncoding.EncodeToString(appKeyHash[:])) + req := httptest.NewRequest(http.MethodPost, pathKey, buf) + e.privSrv.Handler.ServeHTTP(rec, req) + + s := e.hashes.Serialize() + if len(s) != sha256.Size*2 { + t.Fatalf("Expected serialized hashes to be of length %d but got %d.", + sha256.Size*2, len(s)) + } + if !bytes.Equal(s[sha256.Size:], appKeyHash[:]) { + t.Fatalf("Expected application key hash of %x but got %x.", appKeyHash[:], s[sha256.Size:]) + } +} diff --git a/enclave.go b/enclave.go index dc8eda7..4b3f179 100644 --- a/enclave.go +++ b/enclave.go @@ -44,6 +44,7 @@ const ( pathAttestation = "/enclave/attestation" pathState = "/enclave/state" pathSync = "/enclave/sync" + pathKey = "/enclave/key" // All other paths are handled by the enclave application's Web server if // it exists. pathProxy = "/*" @@ -63,7 +64,7 @@ type Enclave struct { cfg *Config pubSrv, privSrv http.Server revProxy *httputil.ReverseProxy - certFpr [sha256.Size]byte + hashes *AttestationHashes nonceCache *cache keyMaterial any stop chan bool @@ -166,12 +167,13 @@ func NewEnclave(cfg *Config) (*Enclave, error) { Handler: chi.NewRouter(), }, nonceCache: newCache(defaultItemExpiry), + hashes: new(AttestationHashes), stop: make(chan bool), } // Register public HTTP API. m := e.pubSrv.Handler.(*chi.Mux) - m.Get(pathAttestation, getAttestationHandler(&e.certFpr)) + m.Get(pathAttestation, getAttestationHandler(e.hashes)) m.Get(pathNonce, getNonceHandler(e)) m.Get(pathRoot, getIndexHandler(e.cfg)) // Register enclave-internal HTTP API. @@ -179,6 +181,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { m.Get(pathSync, syncHandler(e)) m.Get(pathState, getStateHandler(e)) m.Put(pathState, setStateHandler(e)) + m.Post(pathKey, keyHandler(e)) // Configure our reverse proxy if the enclave application exposes an HTTP // server. @@ -399,8 +402,9 @@ func (e *Enclave) setCertFingerprint(rawData []byte) error { return err } if !cert.IsCA { - e.certFpr = sha256.Sum256(cert.Raw) - elog.Printf("Set SHA-256 fingerprint of server's certificate to: %x", e.certFpr[:]) + e.hashes.tlsKeyHash = sha256.Sum256(cert.Raw) + elog.Printf("Set SHA-256 fingerprint of server's certificate to: %x", + e.hashes.tlsKeyHash[:]) return nil } } diff --git a/handlers.go b/handlers.go index 8967b72..e55ff82 100644 --- a/handlers.go +++ b/handlers.go @@ -1,11 +1,14 @@ package nitriding import ( + "crypto/sha256" + "encoding/base64" "errors" "fmt" "io" "net/http" "net/url" + "strings" ) const ( @@ -20,6 +23,7 @@ var ( errFailedReqBody = errors.New("failed to read request body") errFailedGetState = errors.New("failed to retrieve saved state") errNoAddr = errors.New("parameter 'addr' not found") + errHashWrongSize = errors.New("given hash is of invalid size") ) func formatIndexPage(appURL string) string { @@ -114,3 +118,35 @@ func proxyHandler(e *Enclave) http.HandlerFunc { e.revProxy.ServeHTTP(w, r) } } + +// keyHandler returns an HTTP handler that allows the enclave application to +// register a hash over a public key which is going to be included in +// attestation documents. This allows clients to tie the attestation document +// (which acts as the root of trust) to key material that's used by the enclave +// application. +func keyHandler(e *Enclave) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // Allow an extra byte for the \n. + maxReadLen := base64.StdEncoding.EncodedLen(sha256.Size) + 1 + body, err := io.ReadAll(newLimitReader(r.Body, maxReadLen)) + if errors.Is(err, errTooMuchToRead) { + http.Error(w, errTooMuchToRead.Error(), http.StatusBadRequest) + return + } + if err != nil { + http.Error(w, errFailedReqBody.Error(), http.StatusInternalServerError) + } + + keyHash, err := base64.StdEncoding.DecodeString(strings.TrimSpace(string(body))) + if err != nil { + http.Error(w, errNoBase64.Error(), http.StatusBadRequest) + return + } + + if len(keyHash) != sha256.Size { + http.Error(w, errHashWrongSize.Error(), http.StatusBadRequest) + return + } + copy(e.hashes.appKeyHash[:], keyHash) + } +} diff --git a/handlers_test.go b/handlers_test.go index 5a10ece..e0b1cb2 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -2,7 +2,9 @@ package nitriding import ( "bytes" + "crypto/sha256" "crypto/tls" + "encoding/base64" "fmt" "io" "net/http" @@ -113,3 +115,45 @@ func TestProxyHandler(t *testing.T) { } expect(t, resp, http.StatusOK, appPage) } + +func TestKeyHandler(t *testing.T) { + e := createEnclave() + h := keyHandler(e) + validHash := [sha256.Size]byte{} + validHashB64 := base64.StdEncoding.EncodeToString(validHash[:]) + + // Send invalid Base64. + req, _ := http.NewRequest(http.MethodPost, pathKey, bytes.NewBufferString("foo")) + rec := httptest.NewRecorder() + h(rec, req) + expect(t, rec.Result(), http.StatusBadRequest, errNoBase64.Error()) + + // Send invalid hash size. + req.Body = io.NopCloser(bytes.NewBufferString("AAAAAAAAAAAAAA==")) + rec = httptest.NewRecorder() + h(rec, req) + expect(t, rec.Result(), http.StatusBadRequest, errHashWrongSize.Error()) + + // Send too much data. + req.Body = io.NopCloser(bytes.NewBufferString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")) + rec = httptest.NewRecorder() + h(rec, req) + expect(t, rec.Result(), http.StatusBadRequest, errTooMuchToRead.Error()) + + // Finally, send a valid, Base64-encoded SHA-256 hash. + req.Body = io.NopCloser(bytes.NewBufferString(validHashB64)) + rec = httptest.NewRecorder() + h(rec, req) + expect(t, rec.Result(), http.StatusOK, "") + + // Same as above but with an additional \n. + req.Body = io.NopCloser(bytes.NewBufferString(validHashB64 + "\n")) + rec = httptest.NewRecorder() + h(rec, req) + expect(t, rec.Result(), http.StatusOK, "") + + // Make sure that our hash was set correctly. + if e.hashes.appKeyHash != validHash { + t.Fatalf("Application key hash (%x) not as expected (%x).", e.hashes.appKeyHash, validHash) + } +} From efb5580a3b001071b3a8ad6fc35df176a0ae6d25 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Wed, 16 Nov 2022 09:06:38 -0600 Subject: [PATCH 24/55] Add handler to signal readiness. This enclave-internal HTTP handler allows applications to signal their readiness to nitriding. When the handler is called, nitriding starts its Internet-facing Web server. --- attestation_test.go | 1 + enclave.go | 16 +++++++++++++--- handlers.go | 10 ++++++++++ handlers_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/attestation_test.go b/attestation_test.go index c370128..8d0e94b 100644 --- a/attestation_test.go +++ b/attestation_test.go @@ -98,6 +98,7 @@ func TestAttestationHashes(t *testing.T) { t.Fatal(err) } defer e.Stop() //nolint:errcheck + signalReady(t, e) // Register dummy key material for the other hash to be initialized. rec := httptest.NewRecorder() diff --git a/enclave.go b/enclave.go index 4b3f179..0cc3b0c 100644 --- a/enclave.go +++ b/enclave.go @@ -45,6 +45,7 @@ const ( pathState = "/enclave/state" pathSync = "/enclave/sync" pathKey = "/enclave/key" + pathReady = "/enclave/ready" // All other paths are handled by the enclave application's Web server if // it exists. pathProxy = "/*" @@ -67,7 +68,7 @@ type Enclave struct { hashes *AttestationHashes nonceCache *cache keyMaterial any - stop chan bool + ready, stop chan bool } // Config represents the configuration of our enclave service. @@ -169,6 +170,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { nonceCache: newCache(defaultItemExpiry), hashes: new(AttestationHashes), stop: make(chan bool), + ready: make(chan bool), } // Register public HTTP API. @@ -180,6 +182,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { m = e.privSrv.Handler.(*chi.Mux) m.Get(pathSync, syncHandler(e)) m.Get(pathState, getStateHandler(e)) + m.Get(pathReady, readyHandler(e)) m.Put(pathState, setStateHandler(e)) m.Post(pathKey, keyHandler(e)) @@ -256,8 +259,15 @@ func startWebServers(e *Enclave) error { if err != nil { return fmt.Errorf("failed to create unix domain socket: %w", err) } - go e.privSrv.Serve(l) //nolint:errcheck - go e.pubSrv.ListenAndServeTLS("", "") //nolint:errcheck + go e.privSrv.Serve(l) //nolint:errcheck + + // Don't launch our Internet-facing Web server until the application + // signalled that it's ready. + go func() { + <-e.ready + elog.Println("Application signalled that it's ready. Starting public Web server.") + e.pubSrv.ListenAndServeTLS("", "") //nolint:errcheck + }() return nil } diff --git a/handlers.go b/handlers.go index e55ff82..6efa1cd 100644 --- a/handlers.go +++ b/handlers.go @@ -150,3 +150,13 @@ func keyHandler(e *Enclave) http.HandlerFunc { copy(e.hashes.appKeyHash[:], keyHash) } } + +// readyHandler returns an HTTP handler that lets the enclave application +// signal that it's ready, instructing nitriding to start its Internet-facing +// Web server. +func readyHandler(e *Enclave) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + close(e.ready) + w.WriteHeader(http.StatusOK) + } +} diff --git a/handlers_test.go b/handlers_test.go index e0b1cb2..57bc473 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -11,9 +11,21 @@ import ( "net/http/httptest" "net/http/httputil" "net/url" + "strings" "testing" + "time" ) +// signalReady signals to the enclave-internal Web server that we're ready, +// instructing it to spin up its Internet-facing Web server. +func signalReady(t *testing.T, e *Enclave) { + t.Helper() + rec := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodGet, pathReady, nil) + e.privSrv.Handler.ServeHTTP(rec, req) + expect(t, rec.Result(), http.StatusOK, "") +} + func TestSyncHandler(t *testing.T) { e := createEnclave() h := syncHandler(e) @@ -94,6 +106,7 @@ func TestProxyHandler(t *testing.T) { t.Fatal(err) } defer e.Stop() //nolint:errcheck + signalReady(t, e) // Skip certificate validation because we are using a self-signed // certificate in this test. @@ -157,3 +170,34 @@ func TestKeyHandler(t *testing.T) { t.Fatalf("Application key hash (%x) not as expected (%x).", e.hashes.appKeyHash, validHash) } } + +func TestReadyHandler(t *testing.T) { + e := createEnclave() + if err := e.Start(); err != nil { + t.Fatal(err) + } + defer e.Stop() //nolint:errcheck + + // Check if the Internet-facing Web server is running. + nitridingSrv := fmt.Sprintf("https://127.0.0.1:%d", e.cfg.Port) + _, err := http.Get(nitridingSrv + pathRoot) + if !strings.Contains(err.Error(), "connection refused") { + t.Fatal("Expected 'connection refused'.") + } + + signalReady(t, e) + // There's no straightforward way to register a callback for when a Web + // server has started because ListenAndServeTLS blocks for as long as the + // server is alive. Let's wait briefly to give the Web server enough time + // to start. An ugly test is better than no test. + time.Sleep(100 * time.Millisecond) + + // Check again. It should be running this time. + resp, err := http.Get(nitridingSrv + pathRoot) + if err != nil { + t.Fatalf("Expected no error but got %v.", err) + } + if resp.StatusCode != http.StatusOK { + t.Fatalf("Expected status code %d but got %d.", http.StatusOK, resp.StatusCode) + } +} From 80812c1cc9ca19e22b12eb56b444a54a79eb7085 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Wed, 16 Nov 2022 12:58:29 -0600 Subject: [PATCH 25/55] Replace domain socket with TCP port. Domain sockets are great for high-throughput applications but we don't need troughput here; we need ease of use. --- cmd/main.go | 16 ++++++++-------- enclave.go | 34 ++++++++++++++-------------------- enclave_test.go | 16 ++++++++-------- handlers_test.go | 2 +- system.go | 17 ----------------- system_test.go | 14 -------------- 6 files changed, 31 insertions(+), 68 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index aa44c09..71b9971 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -12,22 +12,22 @@ import ( var l = log.New(os.Stderr, "nitriding-cmd: ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile) func main() { - var sockAddr, fqdn, appURL, appWebSrv string - var port, hostProxyPort int + var fqdn, appURL, appWebSrv string + var extPort, intPort, hostProxyPort int var useACME bool var u *url.URL var err error flag.StringVar(&fqdn, "fqdn", "", "FQDN of the enclave application (e.g., \"example.com\").") - flag.StringVar(&sockAddr, "sockaddr", "/tmp/nitriding.sock", - "Path to Unix domain socket for enclave-internal IPC.") flag.StringVar(&appURL, "appurl", "", "Code repository of the enclave application (e.g., \"github.com/foo/bar\").") flag.StringVar(&appWebSrv, "appwebsrv", "", - "Enclave-internal HTTP server of the enclave application (e.g., \"http://127.0.0.1:8080\").") - flag.IntVar(&port, "port", 8443, + "Enclave-internal HTTP server of the enclave application (e.g., \"http://127.0.0.1:8081\").") + flag.IntVar(&extPort, "extport", 8443, "Nitriding's VSOCK-facing HTTPS port. Must match port forwarding rules on EC2 host.") + flag.IntVar(&intPort, "intport", 8080, + "Nitriding's enclave-internal HTTP port. Only used by the enclave application.") flag.IntVar(&hostProxyPort, "host-proxy-port", 1024, "Port of proxy application running on EC2 host.") flag.BoolVar(&useACME, "acme", false, @@ -48,10 +48,10 @@ func main() { enclave, err := nitriding.NewEnclave( &nitriding.Config{ FQDN: fqdn, - Port: port, + ExtPort: extPort, + IntPort: intPort, HostProxyPort: hostProxyPort, UseACME: useACME, - SockAddr: sockAddr, AppURL: appURL, AppWebSrv: u, }, diff --git a/enclave.go b/enclave.go index 0cc3b0c..0e3a57a 100644 --- a/enclave.go +++ b/enclave.go @@ -78,20 +78,20 @@ type Config struct { // is required. FQDN string - // Port contains the TCP port that the Web server should listen on, e.g. - // 8443. Note that the Web server listens for this port on the private - // VSOCK interface. This is not an Internet-facing port. This field is - // required. - Port int + // ExtPort contains the VSOCK-facing TCP port that the Web server should + // listen on, e.g. 8443. This port is not *directly* reachable by the + // Internet but the EC2 host's proxy *does* forward Internet traffic to + // this port. This field is required. + ExtPort int + + // IntPort contains the enclave-internal TCP port of the Web server that + // provides an HTTP API to the enclave application. + IntPort int // HostProxyPort indicates the TCP port of the proxy application running on // the EC2 host. If unset, the default of 1024 is goint to be used. HostProxyPort int - // SockAddr indicates the file system path to the Unix domain socket that - // enclave applications can use to talk to nitriding's HTTP API. - SockAddr string - // UseACME must be set to true if you want your enclave application to // request a Let's Encrypt-signed certificate. If this is set to false, // the enclave creates a self-signed certificate. @@ -133,7 +133,7 @@ func (c *Config) Validate() error { if c.FQDN == "" { return errCfgMissingFQDN } - if c.Port == 0 { + if c.ExtPort == 0 { return errCfgMissingPort } return nil @@ -161,10 +161,11 @@ func NewEnclave(cfg *Config) (*Enclave, error) { e := &Enclave{ cfg: cfg, pubSrv: http.Server{ - Addr: fmt.Sprintf(":%d", cfg.Port), + Addr: fmt.Sprintf(":%d", cfg.ExtPort), Handler: chi.NewRouter(), }, privSrv: http.Server{ + Addr: fmt.Sprintf("127.0.0.1:%d", cfg.IntPort), Handler: chi.NewRouter(), }, nonceCache: newCache(defaultItemExpiry), @@ -244,22 +245,15 @@ func (e *Enclave) Stop() error { if err := e.pubSrv.Shutdown(context.Background()); err != nil { return err } - if err := os.RemoveAll(e.cfg.SockAddr); err != nil { - return err - } return nil } // startWebServers starts both our public-facing and our enclave-internal Web // server in a goroutine. func startWebServers(e *Enclave) error { - elog.Printf("Starting public (%s) and private (%s) Web server.", e.pubSrv.Addr, e.cfg.SockAddr) + elog.Printf("Starting public (%s) and private (%s) Web server.", e.pubSrv.Addr, e.privSrv.Addr) - l, err := createUnixSocket(e.cfg.SockAddr) - if err != nil { - return fmt.Errorf("failed to create unix domain socket: %w", err) - } - go e.privSrv.Serve(l) //nolint:errcheck + go e.privSrv.ListenAndServe() //nolint:errcheck // Don't launch our Internet-facing Web server until the application // signalled that it's ready. diff --git a/enclave_test.go b/enclave_test.go index 56d286d..8e4883e 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -6,13 +6,13 @@ import ( ) var defaultCfg = &Config{ - FQDN: "example.com", - SockAddr: "/tmp/nitriding.sock", - Port: 50000, - UseACME: false, - Debug: false, - FdCur: 1024, - FdMax: 4096, + FQDN: "example.com", + ExtPort: 50000, + IntPort: 50001, + UseACME: false, + Debug: false, + FdCur: 1024, + FdMax: 4096, } func createEnclave() *Enclave { @@ -38,7 +38,7 @@ func TestValidateConfig(t *testing.T) { } // Set the last required field. - c.Port = 1 + c.ExtPort = 1 if err = c.Validate(); err != nil { t.Fatalf("Validation of valid config returned an error.") } diff --git a/handlers_test.go b/handlers_test.go index 57bc473..523ab89 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -179,7 +179,7 @@ func TestReadyHandler(t *testing.T) { defer e.Stop() //nolint:errcheck // Check if the Internet-facing Web server is running. - nitridingSrv := fmt.Sprintf("https://127.0.0.1:%d", e.cfg.Port) + nitridingSrv := fmt.Sprintf("https://127.0.0.1:%d", e.cfg.ExtPort) _, err := http.Get(nitridingSrv + pathRoot) if !strings.Contains(err.Error(), "connection refused") { t.Fatal("Expected 'connection refused'.") diff --git a/system.go b/system.go index 1ae2ed7..2471ce1 100644 --- a/system.go +++ b/system.go @@ -3,8 +3,6 @@ package nitriding import ( "errors" "io" - "net" - "os" "syscall" ) @@ -79,18 +77,3 @@ func setFdLimit(cur, max uint64) error { return nil } - -// createUnixSocket creates a unix domain socket at the given path and returns -// a listener for it. -func createUnixSocket(sockaddr string) (net.Listener, error) { - if err := os.RemoveAll(sockaddr); err != nil { - return nil, err - } - - l, err := net.Listen("unix", sockaddr) - if err != nil { - return nil, err - } - - return l, nil -} diff --git a/system_test.go b/system_test.go index f946521..ee6b309 100644 --- a/system_test.go +++ b/system_test.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "io" - "os" "syscall" "testing" ) @@ -85,16 +84,3 @@ func TestSetFdLimit(t *testing.T) { } checkFdLimit(t, defaultFdCur-1, defaultFdMax-1) } - -func TestCreateUnixSocket(t *testing.T) { - fd, err := os.CreateTemp("/tmp", "domainsock") - if err != nil { - t.Fatalf("Failed to create temporary file: %v", err) - } - defer os.Remove(fd.Name()) - - _, err = createUnixSocket(fd.Name()) - if err != nil { - t.Fatalf("Failed to create unix socket: %v", err) - } -} From f86cd6777424fdc5f899d7131d14c8274aa24cd7 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Wed, 16 Nov 2022 14:17:29 -0600 Subject: [PATCH 26/55] Re-add loopback interface creation. --- enclave.go | 3 +++ system_darwin.go | 3 +++ system_linux.go | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 system_darwin.go create mode 100644 system_linux.go diff --git a/enclave.go b/enclave.go index 0e3a57a..c6265e8 100644 --- a/enclave.go +++ b/enclave.go @@ -213,6 +213,9 @@ func (e *Enclave) Start() error { if err = setFdLimit(e.cfg.FdCur, e.cfg.FdMax); err != nil { elog.Printf("Failed to set new file descriptor limit: %s", err) } + if err = assignLoAddr(); err != nil { + return fmt.Errorf("%s: failed to assign loopback address: %w", errPrefix, err) + } } // Set up our networking environment which creates a TAP device that diff --git a/system_darwin.go b/system_darwin.go new file mode 100644 index 0000000..2c15d9a --- /dev/null +++ b/system_darwin.go @@ -0,0 +1,3 @@ +package nitriding + +func assignLoAddr() error { return nil } diff --git a/system_linux.go b/system_linux.go new file mode 100644 index 0000000..dfbe498 --- /dev/null +++ b/system_linux.go @@ -0,0 +1,27 @@ +package nitriding + +import ( + "net" + + "github.com/milosgajdos/tenus" +) + +// assignLoAddr assigns an IP address to the loopback interface, which is +// necessary because Nitro enclaves don't do that out-of-the-box. We need the +// loopback interface because we run a simple TCP proxy that listens on +// 127.0.0.1:1080 and converts AF_INET to AF_VSOCK. +func assignLoAddr() error { + addrStr := "127.0.0.1/8" + l, err := tenus.NewLinkFrom("lo") + if err != nil { + return err + } + addr, network, err := net.ParseCIDR(addrStr) + if err != nil { + return err + } + if err = l.SetLinkIp(addr, network); err != nil { + return err + } + return l.SetLinkUp() +} From 9ab40125dcf56974da7781a79ba5d3f4dae15559 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Wed, 16 Nov 2022 18:48:15 -0600 Subject: [PATCH 27/55] Add example application. A simple Python client that retrieves its IP address by connecting to a Web server. --- example/Dockerfile | 11 +++++++++++ example/Makefile | 29 +++++++++++++++++++++++++++++ example/README.md | 17 +++++++++++++++++ example/service.py | 28 ++++++++++++++++++++++++++++ example/start.sh | 9 +++++++++ 5 files changed, 94 insertions(+) create mode 100644 example/Dockerfile create mode 100644 example/Makefile create mode 100644 example/README.md create mode 100755 example/service.py create mode 100755 example/start.sh diff --git a/example/Dockerfile b/example/Dockerfile new file mode 100644 index 0000000..492e484 --- /dev/null +++ b/example/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:latest + +RUN mkdir -p /lib64 && ln -sf /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 +RUN apk add --no-cache py3-pip +RUN pip install requests + +COPY nitriding / +COPY service.py / +COPY start.sh / + +CMD ["/start.sh"] diff --git a/example/Makefile b/example/Makefile new file mode 100644 index 0000000..10f1d78 --- /dev/null +++ b/example/Makefile @@ -0,0 +1,29 @@ +.PHONY: all docker enclave kill run clean + +docker_image = python-test +enclave_image = $(docker_image).eif +godeps = ../cmd/*.go ../*.go ../go.mod ../go.sum +binary = nitriding + +all: $(binary) docker enclave kill run + +$(binary): $(godeps) + make -C ../cmd/ + cp ../cmd/nitriding . + +docker: Dockerfile + docker build -t $(docker_image):latest . + +enclave: + nitro-cli build-enclave --docker-uri $(docker_image):latest --output-file $(enclave_image) + +kill: + $(eval ENCLAVE_ID=$(shell nitro-cli describe-enclaves | jq -r '.[0].EnclaveID')) + @if [ "$(ENCLAVE_ID)" != "null" ]; then nitro-cli terminate-enclave --enclave-id $(ENCLAVE_ID); fi + +run: + nitro-cli run-enclave --cpu-count 2 --memory 4000 --enclave-cid 4 --eif-path $(enclave_image) --debug-mode + nitro-cli console --enclave-id $$(nitro-cli describe-enclaves | jq -r '.[0].EnclaveID') + +clean: + rm -f $(binary) diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..cc25f59 --- /dev/null +++ b/example/README.md @@ -0,0 +1,17 @@ +Nitriding example +================= + +This directory contains an example application; a lightweight +[Python script](service.py) +that retrieves its IP address from an HTTP server. The project's +[Dockerfile](Dockerfile) adds the nitriding standalone executable along with the +enclave application, consisting of the +[Python script](service.py) +and a +[shell script](start.sh) +that invokes nitriding in the background, followed by running the Python script. + +To build the nitriding executable, the Docker image, the enclave image, and +finally run the enclave image, simply run: + + make diff --git a/example/service.py b/example/service.py new file mode 100755 index 0000000..87dc982 --- /dev/null +++ b/example/service.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 + +import time +import requests + +nitriding_url = "http://127.0.0.1:8080/enclave/ready" + + +def signal_ready(): + ok = 200 + r = requests.get(url=nitriding_url) + if r.status_code != ok: + raise Exception("Expected status code %d but got %d" % + (ok, r.status_code)) + + +def fetch_addr(): + r = requests.get(url="https://ifconfig.me/ip") + print("[py] Our IP address is: %s" % r.text) + + +if __name__ == "__main__": + signal_ready() + print("[py] Signalled to nitriding that we're ready.") + + time.sleep(1) + fetch_addr() + print("[py] Made Web request to the outside world.") diff --git a/example/start.sh b/example/start.sh new file mode 100755 index 0000000..78c0b6e --- /dev/null +++ b/example/start.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +/nitriding -fqdn example.com -extport 8443 -intport 8080 & +echo "[sh] Started nitriding." + +sleep 1 + +/service.py +echo "[sh] Ran Python script." From e757a4cf6b803e422d1d7a4cf2f73afde471c8ac Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 17 Nov 2022 09:44:18 -0600 Subject: [PATCH 28/55] Rename path from "key" to "hash". The endpoint takes as input a SHA-256 hash, so "hash" better reflects what's going on behind the scenes; "key" is too broad of a term. --- attestation_test.go | 2 +- enclave.go | 4 ++-- handlers_test.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/attestation_test.go b/attestation_test.go index 8d0e94b..ed78d9c 100644 --- a/attestation_test.go +++ b/attestation_test.go @@ -103,7 +103,7 @@ func TestAttestationHashes(t *testing.T) { // Register dummy key material for the other hash to be initialized. rec := httptest.NewRecorder() buf := bytes.NewBufferString(base64.StdEncoding.EncodeToString(appKeyHash[:])) - req := httptest.NewRequest(http.MethodPost, pathKey, buf) + req := httptest.NewRequest(http.MethodPost, pathHash, buf) e.privSrv.Handler.ServeHTTP(rec, req) s := e.hashes.Serialize() diff --git a/enclave.go b/enclave.go index c6265e8..0f21896 100644 --- a/enclave.go +++ b/enclave.go @@ -44,7 +44,7 @@ const ( pathAttestation = "/enclave/attestation" pathState = "/enclave/state" pathSync = "/enclave/sync" - pathKey = "/enclave/key" + pathHash = "/enclave/hash" pathReady = "/enclave/ready" // All other paths are handled by the enclave application's Web server if // it exists. @@ -185,7 +185,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { m.Get(pathState, getStateHandler(e)) m.Get(pathReady, readyHandler(e)) m.Put(pathState, setStateHandler(e)) - m.Post(pathKey, keyHandler(e)) + m.Post(pathHash, keyHandler(e)) // Configure our reverse proxy if the enclave application exposes an HTTP // server. diff --git a/handlers_test.go b/handlers_test.go index 523ab89..df2d5f7 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -136,7 +136,7 @@ func TestKeyHandler(t *testing.T) { validHashB64 := base64.StdEncoding.EncodeToString(validHash[:]) // Send invalid Base64. - req, _ := http.NewRequest(http.MethodPost, pathKey, bytes.NewBufferString("foo")) + req, _ := http.NewRequest(http.MethodPost, pathHash, bytes.NewBufferString("foo")) rec := httptest.NewRecorder() h(rec, req) expect(t, rec.Result(), http.StatusBadRequest, errNoBase64.Error()) From 82c0b1f5340662812d8eba8399c4e8af71e09e0b Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 17 Nov 2022 10:25:04 -0600 Subject: [PATCH 29/55] Update documentation and architecture diagram. --- README.md | 134 ++++++++++++++++++++------------------------ doc/architecture.md | 50 +++++++++++++---- 2 files changed, 99 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 7c48f22..2df4cd9 100644 --- a/README.md +++ b/README.md @@ -2,95 +2,82 @@ [![GoDoc](https://pkg.go.dev/badge/github.com/brave/nitriding?utm_source=godoc)](https://pkg.go.dev/github.com/brave/nitriding) -This package helps with building Go-based Web applications on top of AWS Nitro -Enclaves. The package provides the following features: - -1. Automatically obtains an HTTPS certificate (either self-signed or via [Let's - Encrypt](https://letsencrypt.org)) for clients to securely connect to your - enclave over the Internet. - -2. Automatically exposes an HTTPS endpoint for remote attestation. After - having audited your enclave's source code, your users can conveniently - verify the enclave by using a tool like - [verify-enclave](https://github.com/brave-experiments/verify-enclave) - and running: +This Go tool kit makes it possible to run your application inside an +[AWS Nitro Enclave](https://aws.amazon.com/ec2/nitro/nitro-enclaves/). +Let's assume that you built a Web service in Rust. You can now use nitriding to +move your Rust code into a secure enclave, making it possible for your users to +remotely verify that you are in fact running the code that you claim to run. +Nitriding provides the following features: + +* Automatically obtains an HTTPS certificate (either self-signed or via + [Let's Encrypt](https://letsencrypt.org)) + for clients to securely connect to your enclave over the Internet. Nitriding + can act as a TLS-terminating reverse HTTP proxy for your application, so your + application does not have to deal with obtaining certificates. + +* Automatically exposes an HTTPS endpoint for remote attestation. After having + audited your enclave's source code, your users can conveniently verify the + enclave's image by using a tool like + [verify-enclave](https://github.com/brave-experiments/verify-enclave) + and running: ``` - make verify CODE=/path/to/code/ ENCLAVE=https://example.com/attest + make verify CODE=/path/to/code/ ENCLAVE=https://enclave.com/enclave/attestation ``` -3. Provides an API for the enclave application to securely share confidential - key material with an identical, remote enclave. +* Are you building an application that uses a protocol other than HTTP? If so, + nitriding makes it possible to register a hash over your application's public + key material which is subsequently included in the + [attestation document](https://docs.aws.amazon.com/enclaves/latest/user/nitro-enclave-concepts.html#term-attestdoc). + This allows your users to verify that their connection is securely terminated + inside the enclave, regardless of the protocol that you are using. + +* Provides an API to scale enclave applications horizontally while synchronizing + state between enclaves. -4. Starts a proxy component that transparently translates between IP and VSOCK, - so you can write IP-based networking code without having to worry about - the enclave's constrained VSOCK interface. +* AWS Nitro Enclaves only provide a highly constrained + [VSOCK channel](https://docs.aws.amazon.com/enclaves/latest/user/nitro-enclave-concepts.html#term-socket) + between the enclave and its host. Nitriding creates TAP interface inside the + enclave, allowing your application to transparently access the Internet + without having to worry about VSOCK, port forwarding, or tunneling. -5. Automatically initializes the enclave's entropy pool using the Nitro - hypervisor. +* Automatically initializes the enclave's entropy pool using the Nitro + hypervisor. To learn more about nitriding's trust assumptions, architecture, and build system, take a look at our [research paper](https://arxiv.org/abs/2206.04123). -## Configuration +## Usage -Nitriding's -[configuration object](https://pkg.go.dev/github.com/brave-experiments/nitriding#Config) -contains comments that explain the purpose of each variable. +To use nitriding, the following steps are necessary: -## Example +1. Make sure that your enclave application supports + [reproducible builds](https://reproducible-builds.org); + otherwise, users won't be able to verify your enclave image. -Use the following "hello world" example to get started. The program -instantiates a new Web server that's listening on port 8443, for the domain -example.com. It also registers an HTTP handler for the path `/hello-world` -which, when accessed, simply responds with the string "hello world". +2. Set up + [this proxy application](https://github.com/containers/gvisor-tap-vsock/tree/main/cmd/gvproxy) + on the EC2 host. -Note that in order for this example to work, you need to set up two programs on -the parent EC2 instance: +3. Bundle your application and nitriding together in a Dockerfile. The + nitriding stand-alone executable must be invoked first, followed by your + application. To build the nitriding executable, run `make cmd/nitriding`. + (Then, run `./cmd/nitriding -help` to see a list of command line options.) + For reproducible Docker images, we recommend + [kaniko](https://github.com/GoogleContainerTools/kaniko) + and + [ko](https://github.com/ko-build/ko) (for Go applications only). -1. [viproxy](https://github.com/brave/viproxy) by running: +4. Once your application is done bootstrapping, it must let nitriding know, so + it can start the Internet-facing Web server that handles remote attestation + and other tasks. To do so, the application must issue an HTTP GET request to + `http://127.0.0.1:8080/enclave/ready`. The handler ignores URL parameters + and responds with a status code 200 if the request succeeded. Note that the + port in this example, 8080, is controlled by nitriding's `-intport` command + line flag. - ```bash - export CID=5 # The CID you assigned when running "nitro-cli run-enclave --enclave-cid X ...". - export IN_ADDRS=":8443,:80,3:80" - export OUT_ADDRS="${CID}:8443,${CID}:80,127.0.0.1:1080" - viproxy - ``` - -2. A SOCKS proxy, e.g. - [this one](https://github.com/brave-intl/bat-go/tree/nitro-utils/nitro-shim/tools/socksproxy). - -That said, here is the enclave application: - -```golang -package main - -import ( - "fmt" - "log" - "net/http" - - "github.com/brave/nitriding" -) - -func helloWorldHandler(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "hello world") -} - -func main() { - enclave := nitriding.NewEnclave( - &nitriding.Config{ - FQDN: "example.com", - Port: 8443, - UseACME: true, - }, - ) - enclave.AddRoute(http.MethodGet, "/hello-world", helloWorldHandler) - if err := enclave.Start(); err != nil { - log.Fatalf("Enclave terminated: %v", err) - } -} -``` +Take a look at [this example application](example/) to learn how nitriding works +in practice. ## Development @@ -103,3 +90,4 @@ make ## More documentation * [System architecture](doc/architecture.md) +* [Example application](example/) diff --git a/doc/architecture.md b/doc/architecture.md index 7fc4a29..ca8e7a2 100644 --- a/doc/architecture.md +++ b/doc/architecture.md @@ -11,32 +11,58 @@ ec2->>ec2: Set up proxy Note over ec2,app: Enclave setup starts nitriding->>ec2: Establish TAP tunnel -nitriding->>nitriding: Set up Web servers -app->>app: Set up Web server +nitriding->>nitriding: Set up enclave-internal Web server + +nitriding->>+ec2: Packet forwarding +ec2->>+ca: Request HTTPS certificate (via HTTP-01) +ca-->>-ec2: HTTPS certificate +ec2-->>-nitriding: Packet forwarding + +app->>app: Set up Web or TCP server + +Note over nitriding,app: Only if application runs non-HTTP server. + +opt Register hash over application's public key + app->>+nitriding: POST /enclave/hash + nitriding->>nitriding: Save hash + nitriding-->>-app: OK +end Note over nitriding,app: Only necessary when scaling enclaves. -opt Register key material - app->>+nitriding: PUT /post-keys +opt Register application state + app->>+nitriding: PUT /enclave/state + nitriding->>nitriding: Save state nitriding-->>-app: OK end -nitriding->>+ec2: Packet forwarding -ec2->>+ca: Request HTTPS certificate (via HTTP-01) -ca-->>-ec2: HTTPS certificate -ec2-->>-nitriding: Packet forwarding +app->>+nitriding: GET /enclave/ready +nitriding->>nitriding: Set up external Web server +nitriding-->>-app: OK Note over ec2,app: Enclave setup finished client->>+ec2: GET /attestation?nonce=foobar ec2->>+nitriding: Packet forwarding +nitriding->>nitriding: Ask hypervisor for attestation document nitriding-->>-ec2: Packet forwarding ec2-->>-client: Attestation document client->>client: Verify attestation document -client->>+ec2: GET /hello -ec2->>+app: Packet forwarding -app-->>-ec2: Packet forwarding -ec2-->>-client: "Hello world!" +alt Application runs HTTP server + client->>+ec2: GET /hello + ec2->>+nitriding: Packet forwarding + nitriding->>+app: Reverse proxying + app->>app: Respond to Web request + app-->>-nitriding: Reverse proxying + nitriding-->>-ec2: Packet forwarding + ec2-->>-client: "Hello world!" +else Application runs non-HTTP server + client->>+ec2: TCP connect + ec2->>+app: Packet forwarding + app->>app: Handles TCP connection + app-->>-ec2: Packet forwarding + ec2-->>-client: Connection established +end ``` From 130eb77aadc03daaea6239255e4a3aa66a50e8a4 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 17 Nov 2022 11:50:42 -0600 Subject: [PATCH 30/55] Simplify the way we use autocert. This patch makes use of Let's Encrypt's tls-alpn-01 challenge which is simpler than the http-01 challenge because it does not require a separate listener on port 80. --- certcache.go | 36 ------------------------------------ enclave.go | 9 +-------- enclave_test.go | 12 ------------ 3 files changed, 1 insertion(+), 56 deletions(-) diff --git a/certcache.go b/certcache.go index 2361338..785c667 100644 --- a/certcache.go +++ b/certcache.go @@ -2,19 +2,11 @@ package nitriding import ( "context" - "errors" - "net" - "net/http" "sync" - "github.com/mdlayher/vsock" "golang.org/x/crypto/acme/autocert" ) -var ( - errHTTP01Failed = errors.New("failed to listen for HTTP-01 challenge") -) - // certCache implements the autocert.Cache interface. type certCache struct { sync.RWMutex @@ -53,31 +45,3 @@ func (c *certCache) Delete(ctx context.Context, key string) error { delete(c.cache, key) return nil } - -func listenHTTP01(errChan chan error, mgr *autocert.Manager) { - // Let's Encrypt's HTTP-01 challenge requires a listener on port 80: - // https://letsencrypt.org/docs/challenge-types/#http-01-challenge - var l net.Listener - var err error - - if inEnclave { - l, err = vsock.Listen(uint32(80), nil) - if err != nil { - errChan <- errHTTP01Failed - return - } - defer func() { - _ = l.Close() - }() - } else { - l, err = net.Listen("tcp", ":80") - if err != nil { - errChan <- errHTTP01Failed - return - } - } - - elog.Print("Starting autocert listener.") - errChan <- nil - _ = http.Serve(l, mgr.HTTPHandler(nil)) -} diff --git a/enclave.go b/enclave.go index 0f21896..67577ca 100644 --- a/enclave.go +++ b/enclave.go @@ -360,14 +360,7 @@ func (e *Enclave) setupAcme() error { Prompt: autocert.AcceptTOS, HostPolicy: autocert.HostWhitelist([]string{e.cfg.FQDN}...), } - - errChan := make(chan error) - go listenHTTP01(errChan, &certManager) - if err := <-errChan; err != nil { - return err - } - - e.pubSrv.TLSConfig = &tls.Config{GetCertificate: certManager.GetCertificate} + e.pubSrv.TLSConfig = certManager.TLSConfig() go func() { // Wait until the HTTP-01 listener returned and then check if our new diff --git a/enclave_test.go b/enclave_test.go index 8e4883e..6a551fa 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -1,7 +1,6 @@ package nitriding import ( - "errors" "testing" ) @@ -68,14 +67,3 @@ func TestKeyMaterial(t *testing.T) { t.Fatal("Retrieved key material is unexpected.") } } - -func TestSetupAcme(t *testing.T) { - e := createEnclave() - - // Our autocert code is difficult to test. Simply run it until we hit the - // first error. Better than testing nothing. - expectedErr := errHTTP01Failed - if err := e.setupAcme(); !errors.Is(err, expectedErr) { - t.Fatalf("Expected error %v but got %v.", expectedErr, err) - } -} From 695161d829a4daa4c67fdeab2a657831ea8c921c Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 17 Nov 2022 15:03:24 -0600 Subject: [PATCH 31/55] Add missing Go dependencies. ...and add a -f to rm, while we're at it. --- cmd/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/Makefile b/cmd/Makefile index 670c5f9..72de676 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -1,7 +1,7 @@ .PHONY: all lint clean binary = nitriding -godeps = *.go +godeps = *.go ../*.go ../go.mod ../go.sum all: lint $(binary) @@ -12,4 +12,4 @@ $(binary): $(godeps) go build -o $(binary) clean: - rm $(binary) + rm -f $(binary) From e4c63a9bfa2c028e970947dd18dbc65cb6a3e4f2 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 18 Nov 2022 14:40:55 -0600 Subject: [PATCH 32/55] Make handler naming consistent. --- attestation.go | 13 ++++++------- attestation_test.go | 2 +- enclave.go | 16 +++++++++------- handlers.go | 18 +++++++++--------- handlers_test.go | 8 ++++---- keysync_responder.go | 10 +++++----- keysync_responder_test.go | 18 +++++++++--------- 7 files changed, 43 insertions(+), 42 deletions(-) diff --git a/attestation.go b/attestation.go index b89508a..8829a65 100644 --- a/attestation.go +++ b/attestation.go @@ -49,13 +49,12 @@ func (a *AttestationHashes) Serialize() []byte { return append(a.tlsKeyHash[:], a.appKeyHash[:]...) } -// getAttestationHandler takes as input a SHA-256 hash over an HTTPS -// certificate and returns a HandlerFunc. This HandlerFunc expects a nonce in -// the URL query parameters and subsequently asks its hypervisor for an -// attestation document that contains both the nonce and the certificate hash. -// The resulting Base64-encoded attestation document is then returned to the -// requester. -func getAttestationHandler(hashes *AttestationHashes) http.HandlerFunc { +// attestationHandler takes as input an AttestationHashes struct and returns a +// HandlerFunc. This HandlerFunc expects a nonce in the URL query parameters +// and subsequently asks its hypervisor for an attestation document that +// contains both the nonce and the hashes in the given struct. The resulting +// Base64-encoded attestation document is then returned to the requester. +func attestationHandler(hashes *AttestationHashes) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, errMethodNotGET, http.StatusMethodNotAllowed) diff --git a/attestation_test.go b/attestation_test.go index ed78d9c..c92e574 100644 --- a/attestation_test.go +++ b/attestation_test.go @@ -34,7 +34,7 @@ func expect(t *testing.T, resp *http.Response, statusCode int, errMsg string) { } func testReq(t *testing.T, req *http.Request, statusCode int, errMsg string) { - attestationHandler := getAttestationHandler(&AttestationHashes{}) + attestationHandler := attestationHandler(&AttestationHashes{}) rec := httptest.NewRecorder() attestationHandler(rec, req) expect(t, rec.Result(), statusCode, errMsg) diff --git a/enclave.go b/enclave.go index 67577ca..28a6775 100644 --- a/enclave.go +++ b/enclave.go @@ -176,16 +176,18 @@ func NewEnclave(cfg *Config) (*Enclave, error) { // Register public HTTP API. m := e.pubSrv.Handler.(*chi.Mux) - m.Get(pathAttestation, getAttestationHandler(e.hashes)) - m.Get(pathNonce, getNonceHandler(e)) - m.Get(pathRoot, getIndexHandler(e.cfg)) + m.Get(pathAttestation, attestationHandler(e.hashes)) + m.Get(pathNonce, nonceHandler(e)) + m.Get(pathRoot, rootHandler(e.cfg)) + m.Post(pathSync, respSyncHandler(e, time.Now)) + // Register enclave-internal HTTP API. m = e.privSrv.Handler.(*chi.Mux) - m.Get(pathSync, syncHandler(e)) - m.Get(pathState, getStateHandler(e)) + m.Get(pathSync, reqSyncHandler(e)) m.Get(pathReady, readyHandler(e)) - m.Put(pathState, setStateHandler(e)) - m.Post(pathHash, keyHandler(e)) + m.Get(pathState, getStateHandler(e)) + m.Put(pathState, putStateHandler(e)) + m.Post(pathHash, hashHandler(e)) // Configure our reverse proxy if the enclave application exposes an HTTP // server. diff --git a/handlers.go b/handlers.go index 6efa1cd..c4b6cac 100644 --- a/handlers.go +++ b/handlers.go @@ -36,18 +36,18 @@ func formatIndexPage(appURL string) string { return page } -// getIndexHandler returns an index handler that informs the visitor that this -// host runs inside an enclave. -func getIndexHandler(cfg *Config) http.HandlerFunc { +// rootHandler returns a handler that informs the visitor that this host runs +// inside an enclave. This is useful for testing. +func rootHandler(cfg *Config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, formatIndexPage(cfg.AppURL)) } } -// syncHandler returns a handler that lets the enclave application trigger +// reqSyncHandler returns a handler that lets the enclave application request // state synchronization, which copies the given remote enclave's state into // our state. -func syncHandler(e *Enclave) http.HandlerFunc { +func reqSyncHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() // The 'addr' parameter must have the following form: @@ -96,10 +96,10 @@ func getStateHandler(e *Enclave) http.HandlerFunc { } } -// setStateHandler returns a handler that lets the enclave application set +// putStateHandler returns a handler that lets the enclave application set // state that's synchronized with another enclave in case of horizontal // scaling. The state can be arbitrary bytes. -func setStateHandler(e *Enclave) http.HandlerFunc { +func putStateHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(newLimitReader(r.Body, maxKeyMaterialLen)) if err != nil { @@ -119,12 +119,12 @@ func proxyHandler(e *Enclave) http.HandlerFunc { } } -// keyHandler returns an HTTP handler that allows the enclave application to +// hashHandler returns an HTTP handler that allows the enclave application to // register a hash over a public key which is going to be included in // attestation documents. This allows clients to tie the attestation document // (which acts as the root of trust) to key material that's used by the enclave // application. -func keyHandler(e *Enclave) http.HandlerFunc { +func hashHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Allow an extra byte for the \n. maxReadLen := base64.StdEncoding.EncodedLen(sha256.Size) + 1 diff --git a/handlers_test.go b/handlers_test.go index df2d5f7..a7f7117 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -28,7 +28,7 @@ func signalReady(t *testing.T, e *Enclave) { func TestSyncHandler(t *testing.T) { e := createEnclave() - h := syncHandler(e) + h := reqSyncHandler(e) rec := httptest.NewRecorder() req, err := http.NewRequest(http.MethodGet, pathSync, nil) @@ -43,7 +43,7 @@ func TestSyncHandler(t *testing.T) { func TestStateHandlers(t *testing.T) { expected := []byte{1, 2, 3, 4, 5} // The key material that we're setting and retrieving. e := createEnclave() - setHandler := setStateHandler(e) + setHandler := putStateHandler(e) getHandler := getStateHandler(e) rec := httptest.NewRecorder() req, err := http.NewRequest(http.MethodPut, pathState, bytes.NewReader(expected)) @@ -129,9 +129,9 @@ func TestProxyHandler(t *testing.T) { expect(t, resp, http.StatusOK, appPage) } -func TestKeyHandler(t *testing.T) { +func TestHashHandler(t *testing.T) { e := createEnclave() - h := keyHandler(e) + h := hashHandler(e) validHash := [sha256.Size]byte{} validHashB64 := base64.StdEncoding.EncodeToString(validHash[:]) diff --git a/keysync_responder.go b/keysync_responder.go index fae545c..29f1470 100644 --- a/keysync_responder.go +++ b/keysync_responder.go @@ -28,9 +28,9 @@ var ( type timeFunc func() time.Time -// getNonceHandler returns a HandlerFunc that creates a new nonce and returns -// it to the client. -func getNonceHandler(e *Enclave) http.HandlerFunc { +// nonceHandler returns a HandlerFunc that creates a new nonce and returns it +// to the client. +func nonceHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { nonce, err := newNonce() if err != nil { @@ -43,9 +43,9 @@ func getNonceHandler(e *Enclave) http.HandlerFunc { } } -// getKeysHandler returns a HandlerFunc that shares our secret key material +// respSyncHandler returns a HandlerFunc that shares our secret key material // with the requesting enclave -- after authentication, of course. -func getKeysHandler(e *Enclave, curTime timeFunc) http.HandlerFunc { +func respSyncHandler(e *Enclave, curTime timeFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ourNonce, theirNonce nonce diff --git a/keysync_responder_test.go b/keysync_responder_test.go index 46e98fa..2414157 100644 --- a/keysync_responder_test.go +++ b/keysync_responder_test.go @@ -25,7 +25,7 @@ func queryHandler(handler http.HandlerFunc, path string, reader io.Reader) *http func TestNonceHandler(t *testing.T) { enclave := createEnclave() - res := queryHandler(getNonceHandler(enclave), pathNonce, bytes.NewReader([]byte{})) + res := queryHandler(nonceHandler(enclave), pathNonce, bytes.NewReader([]byte{})) // Did the operation succeed? if res.StatusCode != http.StatusOK { @@ -57,7 +57,7 @@ func TestNonceHandlerIfErr(t *testing.T) { cryptoRead = rand.Read }() - res := queryHandler(getNonceHandler(createEnclave()), pathNonce, bytes.NewReader([]byte{})) + res := queryHandler(nonceHandler(createEnclave()), pathNonce, bytes.NewReader([]byte{})) // Did the operation fail? if res.StatusCode != http.StatusInternalServerError { @@ -72,20 +72,20 @@ func TestNonceHandlerIfErr(t *testing.T) { } } -func TestKeysHandlerForBadReqs(t *testing.T) { +func TestRespSyncHandlerForBadReqs(t *testing.T) { var res *http.Response enclave := createEnclave() // Send non-Base64 bogus data. - res = queryHandler(getKeysHandler(enclave, time.Now), pathState, strings.NewReader("foobar!")) + res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, strings.NewReader("foobar!")) expect(t, res, http.StatusInternalServerError, errNoBase64.Error()) // Send Base64-encoded bogus data. - res = queryHandler(getKeysHandler(enclave, time.Now), pathState, strings.NewReader("Zm9vYmFyCg==")) + res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, strings.NewReader("Zm9vYmFyCg==")) expect(t, res, http.StatusUnauthorized, errFailedVerify.Error()) } -func TestKeysHandler(t *testing.T) { +func TestRespSyncHandler(t *testing.T) { var res *http.Response enclave := createEnclave() enclave.nonceCache.Add(initAttInfo.nonce.B64()) @@ -96,20 +96,20 @@ func TestKeysHandler(t *testing.T) { } currentTime = func() time.Time { return initAttInfo.attDocTime } - res = queryHandler(getKeysHandler(enclave, time.Now), pathState, strings.NewReader(initAttInfo.attDoc)) + res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, strings.NewReader(initAttInfo.attDoc)) // On a non-enclave platform, the responder code will get as far as to // request its attestation document. expect(t, res, http.StatusInternalServerError, errFailedAttestation) } -func TestKeysHandlerDoS(t *testing.T) { +func TestRespSyncHandlerDoS(t *testing.T) { var res *http.Response enclave := createEnclave() // Send more data than the handler should be willing to read. maxSize := base64.StdEncoding.EncodedLen(maxAttDocLen) body := make([]byte, maxSize+1) - res = queryHandler(getKeysHandler(enclave, time.Now), pathState, bytes.NewReader(body)) + res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, bytes.NewReader(body)) expect(t, res, http.StatusInternalServerError, errFailedRespBody.Error()) } From 83863b211a75318cfdcf43d2925af1b856c952fb Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 18 Nov 2022 14:41:26 -0600 Subject: [PATCH 33/55] Move Sleep call to signalReady. --- handlers_test.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/handlers_test.go b/handlers_test.go index a7f7117..c807269 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -24,6 +24,11 @@ func signalReady(t *testing.T, e *Enclave) { req := httptest.NewRequest(http.MethodGet, pathReady, nil) e.privSrv.Handler.ServeHTTP(rec, req) expect(t, rec.Result(), http.StatusOK, "") + // There's no straightforward way to register a callback for when a Web + // server has started because ListenAndServeTLS blocks for as long as the + // server is alive. Let's wait briefly to give the Web server enough time + // to start. An ugly test is better than no test. + time.Sleep(100 * time.Millisecond) } func TestSyncHandler(t *testing.T) { @@ -184,13 +189,7 @@ func TestReadyHandler(t *testing.T) { if !strings.Contains(err.Error(), "connection refused") { t.Fatal("Expected 'connection refused'.") } - signalReady(t, e) - // There's no straightforward way to register a callback for when a Web - // server has started because ListenAndServeTLS blocks for as long as the - // server is alive. Let's wait briefly to give the Web server enough time - // to start. An ugly test is better than no test. - time.Sleep(100 * time.Millisecond) // Check again. It should be running this time. resp, err := http.Get(nitridingSrv + pathRoot) From 8d8133d6ce35f8c1f77fd9f78410124648f7ea63 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 18 Nov 2022 14:43:37 -0600 Subject: [PATCH 34/55] Simplify Makefile. There's no real need for cmddeps. --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5c4a486..59efb70 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,7 @@ .PHONY: all test lint clean binary = cmd/nitriding -godeps = *.go go.mod go.sum -cmddeps = cmd/*.go +godeps = *.go go.mod go.sum cmd/*.go all: test lint $(binary) @@ -12,7 +11,7 @@ lint: test: $(godeps) @go test -cover ./... -$(binary): $(godeps) $(cmddeps) +$(binary): $(godeps) make -C cmd/ clean: From e8b933800888844ce33e349734deadd77ae5d56f Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 18 Nov 2022 14:49:34 -0600 Subject: [PATCH 35/55] Initialize array with a handful of bytes. ...to make the array distinct from the default, which is all 0-bytes. --- attestation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/attestation_test.go b/attestation_test.go index c92e574..167b5a4 100644 --- a/attestation_test.go +++ b/attestation_test.go @@ -90,7 +90,7 @@ func TestArePCRsIdentical(t *testing.T) { func TestAttestationHashes(t *testing.T) { e := createEnclave() - appKeyHash := [sha256.Size]byte{} + appKeyHash := [sha256.Size]byte{1, 2, 3, 4, 5} // Start the enclave. This is going to initialize the hash over the HTTPS // certificate. From 2ed7aba04e40788262f44bf0dd583925b625126a Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 18 Nov 2022 15:10:45 -0600 Subject: [PATCH 36/55] Fix incorrect endpoint. --- keysync_initiator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keysync_initiator.go b/keysync_initiator.go index 46b5f4d..a287fbb 100644 --- a/keysync_initiator.go +++ b/keysync_initiator.go @@ -125,7 +125,7 @@ func requestNonce(addr string) (nonce, error) { func requestAttDoc(addr string, ourAttDoc []byte) ([]byte, error) { errStr := "failed to fetch attestation doc from remote enclave" - endpoint := fmt.Sprintf("%s%s", addr, pathState) + endpoint := fmt.Sprintf("%s%s", addr, pathSync) // Finally, send our attestation document to the remote enclave. If // everything works out, the remote enclave is going to respond with its From e05c1f41a53befcb53b6475a3177891d7d55e04e Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 18 Nov 2022 18:20:49 -0600 Subject: [PATCH 37/55] Use hard-coded IP addresses. So far, nitriding has used DHCP to obtain an IP address, which adds complexity and unnecessary attack surface. This commit replaces our use of DHCP with a hard-coded IP address. --- enclave.go | 7 +++++- go.mod | 19 +++++++---------- go.sum | 57 +++++++++++++------------------------------------ proxy.go | 36 ++++++++----------------------- system_linux.go | 11 ++++------ 5 files changed, 42 insertions(+), 88 deletions(-) diff --git a/enclave.go b/enclave.go index 28a6775..8b35501 100644 --- a/enclave.go +++ b/enclave.go @@ -49,6 +49,11 @@ const ( // All other paths are handled by the enclave application's Web server if // it exists. pathProxy = "/*" + // IP addresses and interface names of our network interfaces. + addrLo = "127.0.0.1/8" + addrTap = "192.168.127.2" + ifaceLo = "lo" + ifaceTap = "tap0" ) var ( @@ -215,7 +220,7 @@ func (e *Enclave) Start() error { if err = setFdLimit(e.cfg.FdCur, e.cfg.FdMax); err != nil { elog.Printf("Failed to set new file descriptor limit: %s", err) } - if err = assignLoAddr(); err != nil { + if err = assignAddrToIface(addrLo, ifaceLo); err != nil { return fmt.Errorf("%s: failed to assign loopback address: %w", errPrefix, err) } } diff --git a/go.mod b/go.mod index c137b36..2ee2de8 100644 --- a/go.mod +++ b/go.mod @@ -3,22 +3,17 @@ module github.com/brave/nitriding go 1.19 require ( - github.com/brave/viproxy v0.1.2 github.com/containers/gvisor-tap-vsock v0.4.0 github.com/go-chi/chi v1.5.4 github.com/go-chi/chi/v5 v5.0.7 - github.com/google/gopacket v1.1.19 github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703 github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9 - github.com/mdlayher/vsock v1.1.1 github.com/milosgajdos/tenus v0.0.3 - github.com/pkg/errors v0.9.1 - github.com/sirupsen/logrus v1.9.0 github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 github.com/vishvananda/netlink v1.2.1-beta.2 - golang.org/x/crypto v0.1.0 - golang.org/x/sys v0.1.0 + golang.org/x/crypto v0.3.0 + golang.org/x/sys v0.2.0 gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf ) @@ -27,11 +22,13 @@ require ( github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 // indirect - github.com/mdlayher/socket v0.2.3 // indirect - github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 // indirect + github.com/mdlayher/socket v0.4.0 // indirect + github.com/mdlayher/vsock v1.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/vishvananda/netns v0.0.1 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/net v0.1.0 // indirect + golang.org/x/net v0.2.0 // indirect golang.org/x/sync v0.1.0 // indirect golang.org/x/text v0.4.0 // indirect - golang.org/x/time v0.1.0 // indirect + golang.org/x/time v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index 0e62faf..3697948 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5 github.com/bazelbuild/rules_go v0.27.0/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/brave/viproxy v0.1.2 h1:sOY8bI1CqLNq+KyRJrEzQuWia81UmLjK5kqTqD284hs= -github.com/brave/viproxy v0.1.2/go.mod h1:E5v9Ajo1sPVAmgDjKDU8fLmkoJeHjtcXJIkEm8XubpQ= github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -190,7 +188,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= @@ -206,11 +203,10 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -246,8 +242,6 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703 h1:oTi0zYvHo1sfk5sevGc4LrfgpLYB6cIhP/HllCUGcZ8= github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703/go.mod h1:ycRhVmo6wegyEl6WN+zXOHUTJvB0J2tiuH88q/McTK8= -github.com/hf/nsm v0.0.0-20211106132757-1ae65a6a69ae h1:oCc+sRCVfMs1iL5yr7zen5K4+HNp4s/jHr+C9TacpWQ= -github.com/hf/nsm v0.0.0-20211106132757-1ae65a6a69ae/go.mod h1:MJsac5D0fKcNWfriUERtln6segcGfD6Nu0V5uGBbPf8= github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9 h1:pU32bJGmZwF4WXb9Yaz0T8vHDtIPVxqDOdmYdwTQPqw= github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9/go.mod h1:MJsac5D0fKcNWfriUERtln6segcGfD6Nu0V5uGBbPf8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -280,7 +274,6 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3 h1:jUp75lepDg0phMUJBCmvaeFDldD2N3S1lBuPwUTszio= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 h1:DZMFueDbfz6PNc1GwDRA8+6lBx1TB9UnxDQliCqR73Y= github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2/go.mod h1:SWzULI85WerrFt3u+nIm5F9l7EvxZTKQvd0InF3nmgM= @@ -296,10 +289,11 @@ github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= -github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= -github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= -github.com/mdlayher/vsock v1.1.1 h1:8lFuiXQnmICBrCIIA9PMgVSke6Fg6V4+r0v7r55k88I= +github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= +github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/mdlayher/vsock v1.1.1/go.mod h1:Y43jzcy7KM3QB+/FK15pfqGxDMCMzUXWegEfIbSM18U= +github.com/mdlayher/vsock v1.2.0 h1:klRY9lndjmg6k/QWbX/ucQ3e2JFRm1M7vfG9hijbQ0A= +github.com/mdlayher/vsock v1.2.0/go.mod h1:w4kdSTQB9p1l/WwGmAs0V62qQ869qRYoongwgN+Y1HE= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/milosgajdos/tenus v0.0.3 h1:jmaJzwaY1DUyYVD0lM4U+uvP2kkEg1VahDqRFxIkVBE= github.com/milosgajdos/tenus v0.0.3/go.mod h1:eIjx29vNeDOYWJuCnaHY2r4fq5egetV26ry3on7p8qY= @@ -366,7 +360,6 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -404,15 +397,13 @@ github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vishvananda/netlink v1.0.1-0.20190930145447-2ec5bdc52b86/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= -github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA= github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs= github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207 h1:nn7SOQy8xCu3iXNv7oiBhhEQtbWdnEOMnuKBlHvrqIM= -github.com/vishvananda/netns v0.0.0-20220913150850-18c4f4234207/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.1 h1:JDkWS7Axy5ziNM3svylLhpSgqjPDb+BgVUbXoDo+iPw= +github.com/vishvananda/netns v0.0.1/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -442,14 +433,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 h1:vJ2V3lFLg+bBhgroYuRfyN583UzVveQmIXjc8T/y3to= -golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -528,10 +513,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220811182439-13a9a731de15 h1:cik0bxZUSJVDyaHf1hZPSDsU8SZHGQZQMeueXCE7yBQ= -golang.org/x/net v0.0.0-20220811182439-13a9a731de15/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -549,8 +532,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -620,12 +601,8 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM= -golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -636,17 +613,15 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= +golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -809,8 +784,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gvisor.dev/gvisor v0.0.0-20220121190119-4f2d380c8b55/go.mod h1:vmN0Pug/s8TJmpnt30DvrEfZ5vDl52psGLU04tFuK2U= -gvisor.dev/gvisor v0.0.0-20221020012913-c40f8e36517d h1:MnKVuMlyvCL/phtPMbHDRrSItO2Mfd6GkWKLgbXOkpE= -gvisor.dev/gvisor v0.0.0-20221020012913-c40f8e36517d/go.mod h1:D0iRe6RVONyvN6uEi/rqBtONyitX5GaHMDDbeMzwgiE= gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf h1:odIYzLMj6x99QKT69c6O8Cc3BNas3oUZPPw74hUzsS0= gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf/go.mod h1:D0iRe6RVONyvN6uEi/rqBtONyitX5GaHMDDbeMzwgiE= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/proxy.go b/proxy.go index f91475e..d7ca26c 100644 --- a/proxy.go +++ b/proxy.go @@ -9,8 +9,6 @@ import ( "io" "net" "net/http" - "os" - "os/exec" "time" "github.com/containers/gvisor-tap-vsock/pkg/transport" @@ -25,8 +23,6 @@ var ( ) const ( - // iface indicates the name of our enclave-internal TAP device. - iface = "tap0" // mac indicates the MAC address of the enclave. mac = "5a:94:ef:e4:0c:ee" ) @@ -50,8 +46,7 @@ func runNetworking(c *Config, stop chan bool) { // 1. Creates a TAP device. // 2. Set up networking links. // 3. Establish a connection with the proxy running on the host. -// 4. Run DHCP to obtain an IP address. -// 5. Spawn goroutines to forward traffic between the TAP device and the proxy +// 4. Spawn goroutines to forward traffic between the TAP device and the proxy // running on the host. func setupNetworking(c *Config, stop chan bool) error { elog.Println("Setting up networking between host and enclave.") @@ -79,7 +74,7 @@ func setupNetworking(c *Config, stop chan bool) error { tap, err := water.New(water.Config{ DeviceType: water.TAP, PlatformSpecificParams: water.PlatformSpecificParams{ - Name: iface, + Name: ifaceTap, MultiQueue: true, }, }) @@ -89,21 +84,21 @@ func setupNetworking(c *Config, stop chan bool) error { defer tap.Close() elog.Println("Created TAP device.") + // Assign an IP address to our freshly creates interface. + if err = assignAddrToIface(addrTap, ifaceTap); err != nil { + return fmt.Errorf("failed to assign tap address: %w", err) + } + // Set up networking links. if err := linkUp(); err != nil { return fmt.Errorf("failed to set MAC address: %w", err) } elog.Println("Created networking link.") - // Spawn goroutines that forward traffic and obtain a DHCP lease. + // Spawn goroutines that forward traffic. errCh := make(chan error, 1) go tx(conn, tap, errCh, mtu) go rx(conn, tap, errCh, mtu) - go func() { - if err := dhcp(); err != nil { - errCh <- fmt.Errorf("failed to run DHCP: %w", err) - } - }() elog.Println("Started goroutines to forward traffic.") select { case err := <-errCh: @@ -115,7 +110,7 @@ func setupNetworking(c *Config, stop chan bool) error { } func linkUp() error { - link, err := netlink.LinkByName(iface) + link, err := netlink.LinkByName(ifaceTap) if err != nil { return err } @@ -132,19 +127,6 @@ func linkUp() error { return netlink.LinkSetUp(link) } -func dhcp() error { - if _, err := exec.LookPath("udhcpc"); err == nil { // busybox dhcp client - cmd := exec.Command("udhcpc", "-f", "-q", "-i", iface, "-v") - cmd.Stderr = os.Stderr - cmd.Stdout = os.Stdout - return cmd.Run() - } - cmd := exec.Command("dhclient", "-4", "-d", "-v", iface) - cmd.Stderr = os.Stderr - cmd.Stdout = os.Stdout - return cmd.Run() -} - func rx(conn net.Conn, tap *water.Interface, errCh chan error, mtu int) { elog.Println("Waiting for frames from enclave application.") var frame ethernet.Frame diff --git a/system_linux.go b/system_linux.go index dfbe498..af23269 100644 --- a/system_linux.go +++ b/system_linux.go @@ -6,13 +6,10 @@ import ( "github.com/milosgajdos/tenus" ) -// assignLoAddr assigns an IP address to the loopback interface, which is -// necessary because Nitro enclaves don't do that out-of-the-box. We need the -// loopback interface because we run a simple TCP proxy that listens on -// 127.0.0.1:1080 and converts AF_INET to AF_VSOCK. -func assignLoAddr() error { - addrStr := "127.0.0.1/8" - l, err := tenus.NewLinkFrom("lo") +// assignAddrToIface assigns the given IP address (in CIDR notation) to the +// given network interface. +func assignAddrToIface(addrStr, iface string) error { + l, err := tenus.NewLinkFrom(iface) if err != nil { return err } From bcac0c92826d5872ada8c0ad9b5389bf981dcd83 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 21 Nov 2022 18:20:20 -0600 Subject: [PATCH 38/55] Finish creation of tap0 interface. This commit wraps up the configuration of the tap0 interface. We configure the interface statically to avoid having to use an in-enclave DHCP client -- an unnecessary security risk. --- enclave.go | 9 ++---- proxy.go | 14 ++++----- system_linux.go | 78 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 81 insertions(+), 20 deletions(-) diff --git a/enclave.go b/enclave.go index 8b35501..6bb727f 100644 --- a/enclave.go +++ b/enclave.go @@ -49,11 +49,6 @@ const ( // All other paths are handled by the enclave application's Web server if // it exists. pathProxy = "/*" - // IP addresses and interface names of our network interfaces. - addrLo = "127.0.0.1/8" - addrTap = "192.168.127.2" - ifaceLo = "lo" - ifaceTap = "tap0" ) var ( @@ -220,8 +215,8 @@ func (e *Enclave) Start() error { if err = setFdLimit(e.cfg.FdCur, e.cfg.FdMax); err != nil { elog.Printf("Failed to set new file descriptor limit: %s", err) } - if err = assignAddrToIface(addrLo, ifaceLo); err != nil { - return fmt.Errorf("%s: failed to assign loopback address: %w", errPrefix, err) + if err = configureLoIface(); err != nil { + return fmt.Errorf("%s: %w", errPrefix, err) } } diff --git a/proxy.go b/proxy.go index d7ca26c..9ca9305 100644 --- a/proxy.go +++ b/proxy.go @@ -22,11 +22,6 @@ var ( mtu = 4000 ) -const ( - // mac indicates the MAC address of the enclave. - mac = "5a:94:ef:e4:0c:ee" -) - // runNetworking calls the function that sets up our networking environment. // If anything fails, we try again after a brief wait period. func runNetworking(c *Config, stop chan bool) { @@ -84,9 +79,12 @@ func setupNetworking(c *Config, stop chan bool) error { defer tap.Close() elog.Println("Created TAP device.") - // Assign an IP address to our freshly creates interface. - if err = assignAddrToIface(addrTap, ifaceTap); err != nil { - return fmt.Errorf("failed to assign tap address: %w", err) + // Configure IP address, MAC address, MTU, default gateway, and DNS. + if err = configureTapIface(); err != nil { + return fmt.Errorf("failed to configure tap interface: %w", err) + } + if err = writeResolvconf(); err != nil { + return fmt.Errorf("failed to create resolv.conf: %w", err) } // Set up networking links. diff --git a/system_linux.go b/system_linux.go index af23269..1a0d6a2 100644 --- a/system_linux.go +++ b/system_linux.go @@ -1,19 +1,29 @@ package nitriding import ( + "fmt" "net" + "os" "github.com/milosgajdos/tenus" ) -// assignAddrToIface assigns the given IP address (in CIDR notation) to the -// given network interface. -func assignAddrToIface(addrStr, iface string) error { - l, err := tenus.NewLinkFrom(iface) +const ( + defaultGw = "192.168.127.1" + addrLo = "127.0.0.1/8" + addrTap = "192.168.127.2/24" + mac = "0f:f1:ce:c0:ff:ee" + ifaceLo = "lo" + ifaceTap = "tap0" +) + +// configureLoIface assigns an IP address to the loopback interface. +func configureLoIface() error { + l, err := tenus.NewLinkFrom(ifaceLo) if err != nil { return err } - addr, network, err := net.ParseCIDR(addrStr) + addr, network, err := net.ParseCIDR(addrLo) if err != nil { return err } @@ -22,3 +32,61 @@ func assignAddrToIface(addrStr, iface string) error { } return l.SetLinkUp() } + +// configureTapIface configures our TAP interface by assigning it a MAC +// address, IP address, and link MTU. We could have used DHCP instead but that +// brings with it unnecessary complexity and attack surface. +func configureTapIface() error { + l, err := tenus.NewLinkFrom(ifaceTap) + if err != nil { + return fmt.Errorf("failed to retrieve link: %w", err) + } + + addr, network, err := net.ParseCIDR(addrTap) + if err != nil { + return fmt.Errorf("failed to parse CIDR: %w", err) + } + if err = l.SetLinkIp(addr, network); err != nil { + return fmt.Errorf("failed to set link address: %w", err) + } + + gw := net.ParseIP(defaultGw) + if err := l.SetLinkDefaultGw(&gw); err != nil { + return fmt.Errorf("failed to set default gateway: %w", err) + } + + if err := l.SetLinkMTU(1500); err != nil { + return fmt.Errorf("failed to set link MTU: %w", err) + } + + if err := l.SetLinkMacAddress(mac); err != nil { + return fmt.Errorf("failed to set MAC address: %w", err) + } + + if err := l.SetLinkUp(); err != nil { + return fmt.Errorf("failed to bring up link: %w", err) + } + + return nil +} + +// writeResolvconf creates our resolv.conf and adds a nameserver. +func writeResolvconf() error { + // A Nitro Enclave's /etc/resolv.conf is a symlink to + // /run/resolvconf/resolv.conf. As of 2022-11-21, the /run/ directory + // exists but not its resolvconf/ subdirectory. + dir := "/run/resolvconf/" + file := dir + "resolv.conf" + + if err := os.MkdirAll(dir, 0755); err != nil { + return fmt.Errorf("failed to create directories: %w", err) + } + + // Our default gateway -- gvproxy -- also operates a DNS resolver. + c := fmt.Sprintf("nameserver %s\n", defaultGw) + if err := os.WriteFile(file, []byte(c), 0644); err != nil { + return fmt.Errorf("failed to write file: %w", err) + } + + return nil +} From c4c72c5898c2f571daefbc31e0740a4782796247 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Mon, 21 Nov 2022 18:35:43 -0600 Subject: [PATCH 39/55] Add clarifying content. Cheers to Ralph for pointing out the lack of explanation. --- handlers.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/handlers.go b/handlers.go index c4b6cac..992463c 100644 --- a/handlers.go +++ b/handlers.go @@ -153,7 +153,12 @@ func hashHandler(e *Enclave) http.HandlerFunc { // readyHandler returns an HTTP handler that lets the enclave application // signal that it's ready, instructing nitriding to start its Internet-facing -// Web server. +// Web server. We initially gate access to the Internet-facing API to avoid +// the issuance of unexpected attestation documents that lack the application's +// hash because the application couldn't register it in time. The downside is +// that state synchronization among enclaves does not work until the +// application signalled its readiness. While not ideal, we chose to ignore +// this for now. func readyHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { close(e.ready) From 6c17bfd5d369cd567ee7fc8c3b8965886cd1a222 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 22 Nov 2022 09:31:21 -0600 Subject: [PATCH 40/55] Don't use multicast MAC address. Least significant bit of the most significant byte indicates a multicast address if set. --- system_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system_linux.go b/system_linux.go index 1a0d6a2..366a9e5 100644 --- a/system_linux.go +++ b/system_linux.go @@ -12,7 +12,7 @@ const ( defaultGw = "192.168.127.1" addrLo = "127.0.0.1/8" addrTap = "192.168.127.2/24" - mac = "0f:f1:ce:c0:ff:ee" + mac = "ba:aa:ad:c0:ff:ee" ifaceLo = "lo" ifaceTap = "tap0" ) From 6990ac2ec31e3a296c892022b3ae27b9fc194370 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 22 Nov 2022 09:33:12 -0600 Subject: [PATCH 41/55] Set default gateway after activating link. ...otherwise, the operation fails. --- system_linux.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/system_linux.go b/system_linux.go index 366a9e5..f29994c 100644 --- a/system_linux.go +++ b/system_linux.go @@ -50,11 +50,6 @@ func configureTapIface() error { return fmt.Errorf("failed to set link address: %w", err) } - gw := net.ParseIP(defaultGw) - if err := l.SetLinkDefaultGw(&gw); err != nil { - return fmt.Errorf("failed to set default gateway: %w", err) - } - if err := l.SetLinkMTU(1500); err != nil { return fmt.Errorf("failed to set link MTU: %w", err) } @@ -67,6 +62,11 @@ func configureTapIface() error { return fmt.Errorf("failed to bring up link: %w", err) } + gw := net.ParseIP(defaultGw) + if err := l.SetLinkDefaultGw(&gw); err != nil { + return fmt.Errorf("failed to set default gateway: %w", err) + } + return nil } From 621b1e4335fe6f334ea661874ff1bff17dbfc6f5 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 22 Nov 2022 09:37:39 -0600 Subject: [PATCH 42/55] Use requests.status_codes.codes.ok instead of 200. --- example/service.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/example/service.py b/example/service.py index 87dc982..2e1fa63 100755 --- a/example/service.py +++ b/example/service.py @@ -7,11 +7,10 @@ def signal_ready(): - ok = 200 r = requests.get(url=nitriding_url) - if r.status_code != ok: + if r.status_code != requests.status_codes.codes.ok: raise Exception("Expected status code %d but got %d" % - (ok, r.status_code)) + (requests.status_codes.codes.ok, r.status_code)) def fetch_addr(): From 41d8af841da98e51f63363b3d47c368d13afe63d Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 22 Nov 2022 09:37:56 -0600 Subject: [PATCH 43/55] Invoke r.raise_for_status() after request. --- example/service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/example/service.py b/example/service.py index 2e1fa63..38f13d8 100755 --- a/example/service.py +++ b/example/service.py @@ -15,6 +15,7 @@ def signal_ready(): def fetch_addr(): r = requests.get(url="https://ifconfig.me/ip") + r.raise_for_status() print("[py] Our IP address is: %s" % r.text) From a8324194cd7404aa373f1c4c7d47b23779691119 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 22 Nov 2022 09:43:51 -0600 Subject: [PATCH 44/55] Don't mix chi's major version numbers. This commit removes the chi import that's not part of its v5 API. It also initializes chi's middleware before we create routes because chi requires that. --- enclave.go | 12 ++++++------ go.mod | 1 - go.sum | 2 -- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/enclave.go b/enclave.go index 6bb727f..130fd78 100644 --- a/enclave.go +++ b/enclave.go @@ -23,8 +23,8 @@ import ( "sync" "time" - "github.com/go-chi/chi/middleware" "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" "github.com/brave/nitriding/randseed" "golang.org/x/crypto/acme/autocert" @@ -174,6 +174,11 @@ func NewEnclave(cfg *Config) (*Enclave, error) { ready: make(chan bool), } + if cfg.Debug { + e.pubSrv.Handler.(*chi.Mux).Use(middleware.Logger) + e.privSrv.Handler.(*chi.Mux).Use(middleware.Logger) + } + // Register public HTTP API. m := e.pubSrv.Handler.(*chi.Mux) m.Get(pathAttestation, attestationHandler(e.hashes)) @@ -196,11 +201,6 @@ func NewEnclave(cfg *Config) (*Enclave, error) { e.pubSrv.Handler.(*chi.Mux).Handle(pathProxy, proxyHandler(e)) } - if cfg.Debug { - e.pubSrv.Handler.(*chi.Mux).Use(middleware.Logger) - e.privSrv.Handler.(*chi.Mux).Use(middleware.Logger) - } - return e, nil } diff --git a/go.mod b/go.mod index 2ee2de8..81e05e9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.19 require ( github.com/containers/gvisor-tap-vsock v0.4.0 - github.com/go-chi/chi v1.5.4 github.com/go-chi/chi/v5 v5.0.7 github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703 github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9 diff --git a/go.sum b/go.sum index 3697948..f94a702 100644 --- a/go.sum +++ b/go.sum @@ -132,8 +132,6 @@ github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= -github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= From 9906e9071347eed74808e6c4a3cda262e2c1cf04 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Wed, 23 Nov 2022 11:23:15 -0600 Subject: [PATCH 45/55] Validate all command line arguments. This commit 1) ensures that all required command line arguments are present and 2) validates the arguments' values. This commit also changes the type of some configuration variables to more appropriate types, e.g., uint16 for AF_INET port numbers. --- cmd/main.go | 53 +++++++++++++++++++++++++++++++++---------------- enclave.go | 20 ++++++++++--------- enclave_test.go | 19 ++++++++++-------- handlers.go | 6 +++--- 4 files changed, 61 insertions(+), 37 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 71b9971..0391f17 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,13 +9,18 @@ import ( "github.com/brave/nitriding" ) +const ( + uint16Max = 0xffff + uint32Max = 0xffffffff +) + var l = log.New(os.Stderr, "nitriding-cmd: ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile) func main() { var fqdn, appURL, appWebSrv string - var extPort, intPort, hostProxyPort int + var extPort, intPort int + var hostProxyPort int64 var useACME bool - var u *url.URL var err error flag.StringVar(&fqdn, "fqdn", "", @@ -28,34 +33,48 @@ func main() { "Nitriding's VSOCK-facing HTTPS port. Must match port forwarding rules on EC2 host.") flag.IntVar(&intPort, "intport", 8080, "Nitriding's enclave-internal HTTP port. Only used by the enclave application.") - flag.IntVar(&hostProxyPort, "host-proxy-port", 1024, + flag.Int64Var(&hostProxyPort, "host-proxy-port", 1024, "Port of proxy application running on EC2 host.") flag.BoolVar(&useACME, "acme", false, "Use Let's Encrypt's ACME to fetch HTTPS certificate.") flag.Parse() - if useACME && fqdn == "" { - l.Fatalf("Fully qualified domain name not given. Use the -fqdn flag.") + if fqdn == "" { + l.Fatalf("-fqdn must be set.") + } + if extPort < 1 || extPort > uint16Max { + l.Fatalf("-extport must be in interval [1, %d]", uint16Max) + } + if intPort < 1 || intPort > uint16Max { + l.Fatalf("-intport must be in interval [1, %d]", uint16Max) + } + if hostProxyPort < 1 || hostProxyPort > uint32Max { + l.Fatalf("-host-proxy-port must be in interval [1, %d]", uint32Max) } + c := &nitriding.Config{ + FQDN: fqdn, + ExtPort: uint16(extPort), + IntPort: uint16(intPort), + HostProxyPort: uint32(hostProxyPort), + UseACME: useACME, + } + if appURL != "" { + u, err := url.Parse(appURL) + if err != nil { + l.Fatalf("Failed to parse application URL: %v", err) + } + c.AppURL = u + } if appWebSrv != "" { - u, err = url.Parse(appWebSrv) + u, err := url.Parse(appWebSrv) if err != nil { l.Fatalf("Failed to parse URL of Web server: %v", err) } + c.AppWebSrv = u } - enclave, err := nitriding.NewEnclave( - &nitriding.Config{ - FQDN: fqdn, - ExtPort: extPort, - IntPort: intPort, - HostProxyPort: hostProxyPort, - UseACME: useACME, - AppURL: appURL, - AppWebSrv: u, - }, - ) + enclave, err := nitriding.NewEnclave(c) if err != nil { l.Fatalf("Failed to create enclave: %v", err) } diff --git a/enclave.go b/enclave.go index 130fd78..c40fa7a 100644 --- a/enclave.go +++ b/enclave.go @@ -82,15 +82,17 @@ type Config struct { // listen on, e.g. 8443. This port is not *directly* reachable by the // Internet but the EC2 host's proxy *does* forward Internet traffic to // this port. This field is required. - ExtPort int + ExtPort uint16 // IntPort contains the enclave-internal TCP port of the Web server that - // provides an HTTP API to the enclave application. - IntPort int + // provides an HTTP API to the enclave application. This field is + // required. + IntPort uint16 // HostProxyPort indicates the TCP port of the proxy application running on - // the EC2 host. If unset, the default of 1024 is goint to be used. - HostProxyPort int + // the EC2 host. Note that VSOCK ports are 32 bits large. This field is + // required. + HostProxyPort uint32 // UseACME must be set to true if you want your enclave application to // request a Let's Encrypt-signed certificate. If this is set to false, @@ -117,7 +119,7 @@ type Config struct { // running inside the enclave, e.g., "https://github.com/foo/bar". The URL // is shown on the enclave's index page, as part of instructions on how to // do remote attestation. - AppURL string + AppURL *url.URL // AppWebSrv should be set to the enclave-internal Web server of the // enclave application, e.g., "http://127.0.0.1:8080". Nitriding acts as a @@ -130,12 +132,12 @@ type Config struct { // Validate returns an error if required fields in the config are not set. func (c *Config) Validate() error { + if c.ExtPort == 0 || c.IntPort == 0 || c.HostProxyPort == 0 { + return errCfgMissingPort + } if c.FQDN == "" { return errCfgMissingFQDN } - if c.ExtPort == 0 { - return errCfgMissingPort - } return nil } diff --git a/enclave_test.go b/enclave_test.go index 6a551fa..2b431bb 100644 --- a/enclave_test.go +++ b/enclave_test.go @@ -5,13 +5,14 @@ import ( ) var defaultCfg = &Config{ - FQDN: "example.com", - ExtPort: 50000, - IntPort: 50001, - UseACME: false, - Debug: false, - FdCur: 1024, - FdMax: 4096, + FQDN: "example.com", + ExtPort: 50000, + IntPort: 50001, + HostProxyPort: 1024, + UseACME: false, + Debug: false, + FdCur: 1024, + FdMax: 4096, } func createEnclave() *Enclave { @@ -36,8 +37,10 @@ func TestValidateConfig(t *testing.T) { t.Fatalf("Validation of invalid config did not return an error.") } - // Set the last required field. + // Set the remaining required fields. c.ExtPort = 1 + c.IntPort = 1 + c.HostProxyPort = 1 if err = c.Validate(); err != nil { t.Fatalf("Validation of valid config returned an error.") } diff --git a/handlers.go b/handlers.go index 992463c..1104fc5 100644 --- a/handlers.go +++ b/handlers.go @@ -26,12 +26,12 @@ var ( errHashWrongSize = errors.New("given hash is of invalid size") ) -func formatIndexPage(appURL string) string { +func formatIndexPage(appURL *url.URL) string { page := indexPage - if appURL != "" { + if appURL != nil { page += fmt.Sprintf("\nIt runs the following code: %s\n"+ "Use the following tool to verify the enclave: "+ - "https://github.com/brave-experiments/verify-enclave", appURL) + "https://github.com/brave-experiments/verify-enclave", appURL.String()) } return page } From c568165c8df906a78c0305b06c62bdee0f92d812 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Wed, 23 Nov 2022 12:22:31 -0600 Subject: [PATCH 46/55] Add prefix to serialized attestation hashes. This is going to facilitate the transition to a different hash function. --- attestation.go | 10 +++++++++- attestation_test.go | 21 +++++++++++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/attestation.go b/attestation.go index 8829a65..1806be2 100644 --- a/attestation.go +++ b/attestation.go @@ -19,6 +19,8 @@ const ( nonceLen = 20 // The size of a nonce in bytes. nonceNumDigits = nonceLen * 2 // The number of hex digits in a nonce. maxAttDocLen = 5000 // A (reasonable?) upper limit for attestation doc lengths. + hashPrefix = "sha256:" + hashSeparator = ";" ) var ( @@ -46,7 +48,13 @@ type AttestationHashes struct { // that all hashes are always present. If a hash was not initialized, it's set // to 0-bytes. func (a *AttestationHashes) Serialize() []byte { - return append(a.tlsKeyHash[:], a.appKeyHash[:]...) + str := fmt.Sprintf("%s%s%s%s%s", + hashPrefix, + a.tlsKeyHash, + hashSeparator, + hashPrefix, + a.appKeyHash) + return []byte(str) } // attestationHandler takes as input an AttestationHashes struct and returns a diff --git a/attestation_test.go b/attestation_test.go index 167b5a4..3bfe92a 100644 --- a/attestation_test.go +++ b/attestation_test.go @@ -107,11 +107,24 @@ func TestAttestationHashes(t *testing.T) { e.privSrv.Handler.ServeHTTP(rec, req) s := e.hashes.Serialize() - if len(s) != sha256.Size*2 { + expectedLen := sha256.Size*2 + len(hashPrefix)*2 + len(hashSeparator) + if len(s) != expectedLen { t.Fatalf("Expected serialized hashes to be of length %d but got %d.", - sha256.Size*2, len(s)) + expectedLen, len(s)) } - if !bytes.Equal(s[sha256.Size:], appKeyHash[:]) { - t.Fatalf("Expected application key hash of %x but got %x.", appKeyHash[:], s[sha256.Size:]) + + // Make sure that the serialized slice starts with "sha256:". + prefix := []byte(hashPrefix) + if !bytes.Equal(s[:len(prefix)], prefix) { + t.Fatalf("Expected prefix %s but got %s.", prefix, s[:len(prefix)]) + } + + // Make sure that our previously-set hash is as expected. + expected := []byte(hashSeparator) + expected = append(expected, []byte(hashPrefix)...) + expected = append(expected, appKeyHash[:]...) + offset := len(hashPrefix) + sha256.Size + if !bytes.Equal(s[offset:], expected) { + t.Fatalf("Expected application key hash of %x but got %x.", expected, s[offset:]) } } From 7b6f27e3e1f3882fa3641a35d975e371ef3417d3 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 24 Nov 2022 07:56:26 -0600 Subject: [PATCH 47/55] Add FIXME and refer to GitHub issue. --- handlers.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/handlers.go b/handlers.go index 1104fc5..12b4e8f 100644 --- a/handlers.go +++ b/handlers.go @@ -47,6 +47,8 @@ func rootHandler(cfg *Config) http.HandlerFunc { // reqSyncHandler returns a handler that lets the enclave application request // state synchronization, which copies the given remote enclave's state into // our state. +// +// FIXME: https://github.com/brave/nitriding/issues/44 func reqSyncHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() From de88f4d9fb0c3540e2c44a7a28c606605876ae64 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Thu, 24 Nov 2022 08:05:17 -0600 Subject: [PATCH 48/55] Use latest Go version in GitHub action. --- .github/workflows/golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 7ef95f6..388a1ce 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/setup-go@v3 with: - go-version: 1.17 + go-version: 1.19 - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 From b78c4b8275ebaf045f81e8d859ab997354b37873 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 29 Nov 2022 08:21:56 -0600 Subject: [PATCH 49/55] Replace our own constants with the ones from math. This adds clarity. --- cmd/main.go | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 0391f17..ad024ff 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -3,17 +3,13 @@ package main import ( "flag" "log" + "math" "net/url" "os" "github.com/brave/nitriding" ) -const ( - uint16Max = 0xffff - uint32Max = 0xffffffff -) - var l = log.New(os.Stderr, "nitriding-cmd: ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile) func main() { @@ -42,14 +38,14 @@ func main() { if fqdn == "" { l.Fatalf("-fqdn must be set.") } - if extPort < 1 || extPort > uint16Max { - l.Fatalf("-extport must be in interval [1, %d]", uint16Max) + if extPort < 1 || extPort > math.MaxUint16 { + l.Fatalf("-extport must be in interval [1, %d]", math.MaxUint16) } - if intPort < 1 || intPort > uint16Max { - l.Fatalf("-intport must be in interval [1, %d]", uint16Max) + if intPort < 1 || intPort > math.MaxUint16 { + l.Fatalf("-intport must be in interval [1, %d]", math.MaxUint16) } - if hostProxyPort < 1 || hostProxyPort > uint32Max { - l.Fatalf("-host-proxy-port must be in interval [1, %d]", uint32Max) + if hostProxyPort < 1 || hostProxyPort > math.MaxUint32 { + l.Fatalf("-host-proxy-port must be in interval [1, %d]", math.MaxUint32) } c := &nitriding.Config{ From a098ea393b43b5ac00e4051901fe4f0447dfea66 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 29 Nov 2022 08:32:59 -0600 Subject: [PATCH 50/55] Use flag.UintVar for all ports. There's no reason to allow negative ports and Go's spec guarantees that a uint is at least 32 bits -- the size of an AF_VSOCK port. --- cmd/main.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index ad024ff..4b5f7a5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -14,8 +14,7 @@ var l = log.New(os.Stderr, "nitriding-cmd: ", log.Ldate|log.Ltime|log.LUTC|log.L func main() { var fqdn, appURL, appWebSrv string - var extPort, intPort int - var hostProxyPort int64 + var extPort, intPort, hostProxyPort uint var useACME bool var err error @@ -25,11 +24,11 @@ func main() { "Code repository of the enclave application (e.g., \"github.com/foo/bar\").") flag.StringVar(&appWebSrv, "appwebsrv", "", "Enclave-internal HTTP server of the enclave application (e.g., \"http://127.0.0.1:8081\").") - flag.IntVar(&extPort, "extport", 8443, + flag.UintVar(&extPort, "extport", 8443, "Nitriding's VSOCK-facing HTTPS port. Must match port forwarding rules on EC2 host.") - flag.IntVar(&intPort, "intport", 8080, + flag.UintVar(&intPort, "intport", 8080, "Nitriding's enclave-internal HTTP port. Only used by the enclave application.") - flag.Int64Var(&hostProxyPort, "host-proxy-port", 1024, + flag.UintVar(&hostProxyPort, "host-proxy-port", 1024, "Port of proxy application running on EC2 host.") flag.BoolVar(&useACME, "acme", false, "Use Let's Encrypt's ACME to fetch HTTPS certificate.") From 8710b38554aa76eb48653ad0c331c04f9d32ad9d Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 29 Nov 2022 08:39:32 -0600 Subject: [PATCH 51/55] Install requests via apk instead of pip. Ralph measured that this saves around 20 MB of space. --- example/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/example/Dockerfile b/example/Dockerfile index 492e484..233b311 100644 --- a/example/Dockerfile +++ b/example/Dockerfile @@ -1,8 +1,7 @@ FROM alpine:latest RUN mkdir -p /lib64 && ln -sf /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 -RUN apk add --no-cache py3-pip -RUN pip install requests +RUN apk add --no-cache py3-requests COPY nitriding / COPY service.py / From 94d7d99aaa2ecd035589875ebf6a6e6aba433877 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 20 Jan 2023 08:10:16 -0600 Subject: [PATCH 52/55] Delete outdated references to HTTP-01 challenge. --- doc/architecture.md | 2 +- enclave.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/architecture.md b/doc/architecture.md index ca8e7a2..f09274a 100644 --- a/doc/architecture.md +++ b/doc/architecture.md @@ -14,7 +14,7 @@ nitriding->>ec2: Establish TAP tunnel nitriding->>nitriding: Set up enclave-internal Web server nitriding->>+ec2: Packet forwarding -ec2->>+ca: Request HTTPS certificate (via HTTP-01) +ec2->>+ca: Request HTTPS certificate (via TLS-ALPN-01) ca-->>-ec2: HTTPS certificate ec2-->>-nitriding: Packet forwarding diff --git a/enclave.go b/enclave.go index c40fa7a..0622e45 100644 --- a/enclave.go +++ b/enclave.go @@ -367,8 +367,6 @@ func (e *Enclave) setupAcme() error { e.pubSrv.TLSConfig = certManager.TLSConfig() go func() { - // Wait until the HTTP-01 listener returned and then check if our new - // certificate is cached. var rawData []byte for { // Get the SHA-1 hash over our leaf certificate. From beed0b9606eda4e633330f16bb53d7ff01f4b2f9 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 20 Jan 2023 08:20:55 -0600 Subject: [PATCH 53/55] Update to latest dependencies. Note that we have to run `go get gvisor.dev/gvisor/runsc@go` in addition to `go get -u` because we need gvisor/runsc's Go branch: https://github.com/google/gvisor#using-go-get --- go.mod | 31 ++++++++++++++++++++++--------- go.sum | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 81e05e9..e824db0 100644 --- a/go.mod +++ b/go.mod @@ -3,31 +3,44 @@ module github.com/brave/nitriding go 1.19 require ( - github.com/containers/gvisor-tap-vsock v0.4.0 - github.com/go-chi/chi/v5 v5.0.7 + github.com/containers/gvisor-tap-vsock v0.5.0 + github.com/go-chi/chi/v5 v5.0.8 github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703 github.com/hf/nsm v0.0.0-20220930140112-cd181bd646b9 github.com/milosgajdos/tenus v0.0.3 github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 github.com/vishvananda/netlink v1.2.1-beta.2 - golang.org/x/crypto v0.3.0 - golang.org/x/sys v0.2.0 - gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf + golang.org/x/crypto v0.5.0 + golang.org/x/sys v0.4.0 + gvisor.dev/gvisor v0.0.0-20230120050912-b6da4fed55f0 ) require ( + github.com/bazelbuild/rules_go v0.30.0 // indirect + github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422 // indirect + github.com/cilium/ebpf v0.4.0 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/docker/libcontainer v2.2.1+incompatible // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/gofrs/flock v0.8.0 // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8 // indirect + github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1 // indirect github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 // indirect github.com/mdlayher/socket v0.4.0 // indirect github.com/mdlayher/vsock v1.2.0 // indirect + github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9 // indirect + github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/vishvananda/netns v0.0.1 // indirect + github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // indirect + github.com/vishvananda/netns v0.0.3 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/net v0.2.0 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/net v0.5.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/text v0.4.0 // indirect - golang.org/x/time v0.2.0 // indirect + golang.org/x/text v0.6.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect ) diff --git a/go.sum b/go.sum index f94a702..8df58f1 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,11 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/bazelbuild/rules_go v0.27.0/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= +github.com/bazelbuild/rules_go v0.30.0 h1:kX4jVcstqrsRqKPJSn2mq2o+TI21edRzEJSrEOMQtr0= +github.com/bazelbuild/rules_go v0.30.0/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422 h1:8eZxmY1yvxGHzdzTEhI09npjMVGzNAdrqzruTX6jcK4= github.com/cenkalti/backoff v1.1.1-0.20190506075156-2146c9339422/go.mod h1:b6Nc7NRH5C4aCISLry0tLnTjcuTEvoiqcWDdsU0sOGM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -65,6 +68,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.4.0 h1:QlHdikaxALkqWasW8hAC1mfR0jdmvbfaBdBPFmRSglA= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -92,12 +96,16 @@ github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kw github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/containers/gvisor-tap-vsock v0.4.0 h1:sPu8OWiboCBJE/VJyxKOikslCI3sAApNfl3jPXdzBRw= github.com/containers/gvisor-tap-vsock v0.4.0/go.mod h1:2daFkw9Qp3NTz7+SLEIeSEZsQbxvJVoPVF5WtRy7h/4= +github.com/containers/gvisor-tap-vsock v0.5.0 h1:hoCkrfQ96tjek2BtiW1BHy50zAQCzkqeiAQY96y6NLk= +github.com/containers/gvisor-tap-vsock v0.5.0/go.mod h1:jrnI5plQtmys5LEKpXcCCrLqZlrHsozQg0V2Jw1UG74= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/stream-metadata-go v0.3.0/go.mod h1:RTjQyHgO/G37oJ3qnqYK6Z4TPZ5EsaabOtfMjVXmgko= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -134,6 +142,8 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -148,6 +158,9 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -217,6 +230,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8 h1:8nlgEAjIalk6uj/CGKCdOO8CQqTeysvcW4RFZ6HbkGM= github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/tcpproxy v0.0.0-20200125044825-b6bb9b5b8252/go.mod h1:DavVbd41y+b7ukKDmlnPR4nGYmkWXR6vHUkjQNiHPBs= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -270,6 +284,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1 h1:zc0R6cOw98cMengLA0fvU55mqbnN7sd/tBMLzSejp+M= github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= @@ -302,6 +317,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9 h1:Sha2bQdoWE5YQPTlJOL31rmce94/tYi113SlFo1xQ2c= github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -327,6 +343,7 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a h1:9iT75RHhYHWwWRlVWU7wnmtFulYcURCglzQOpT+cAF8= github.com/opencontainers/runtime-spec v1.0.3-0.20211123151946-c2389c3cb60a/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -388,6 +405,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= @@ -402,6 +420,8 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1 github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.1 h1:JDkWS7Axy5ziNM3svylLhpSgqjPDb+BgVUbXoDo+iPw= github.com/vishvananda/netns v0.0.1/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.3 h1:WxY6MpgIdDMQX50UJ7bPIRJdBCOeUV6XtW8dZZja988= +github.com/vishvananda/netns v0.0.3/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -433,6 +453,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -466,6 +488,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -513,6 +537,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -601,6 +627,8 @@ golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -614,12 +642,16 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -760,6 +792,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -784,6 +817,10 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81 gvisor.dev/gvisor v0.0.0-20220121190119-4f2d380c8b55/go.mod h1:vmN0Pug/s8TJmpnt30DvrEfZ5vDl52psGLU04tFuK2U= gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf h1:odIYzLMj6x99QKT69c6O8Cc3BNas3oUZPPw74hUzsS0= gvisor.dev/gvisor v0.0.0-20221020013634-8e6a0b996cdf/go.mod h1:D0iRe6RVONyvN6uEi/rqBtONyitX5GaHMDDbeMzwgiE= +gvisor.dev/gvisor v0.0.0-20230120050049-cc0dc87fa27d h1:AlEztVdR4/JpZ6H6jLn4emZjz0GxNtwZky6nlePV674= +gvisor.dev/gvisor v0.0.0-20230120050049-cc0dc87fa27d/go.mod h1:94x/o/BlxPAbw4phqHRac0/IzpcQRUP7ZQldDWV3TKU= +gvisor.dev/gvisor v0.0.0-20230120050912-b6da4fed55f0 h1:Yzd9ezp0lE3VtdTQUdkM7IJAeafJ/Ycpg+22jWOC2LA= +gvisor.dev/gvisor v0.0.0-20230120050912-b6da4fed55f0/go.mod h1:94x/o/BlxPAbw4phqHRac0/IzpcQRUP7ZQldDWV3TKU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From c850d56d687c9df8b6601f150845c4c9c15e9c94 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Fri, 20 Jan 2023 08:42:08 -0600 Subject: [PATCH 54/55] Remove unused curTime argument. --- enclave.go | 2 +- keysync_responder.go | 5 +---- keysync_responder_test.go | 8 ++++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/enclave.go b/enclave.go index 0622e45..b5a29b7 100644 --- a/enclave.go +++ b/enclave.go @@ -186,7 +186,7 @@ func NewEnclave(cfg *Config) (*Enclave, error) { m.Get(pathAttestation, attestationHandler(e.hashes)) m.Get(pathNonce, nonceHandler(e)) m.Get(pathRoot, rootHandler(e.cfg)) - m.Post(pathSync, respSyncHandler(e, time.Now)) + m.Post(pathSync, respSyncHandler(e)) // Register enclave-internal HTTP API. m = e.privSrv.Handler.(*chi.Mux) diff --git a/keysync_responder.go b/keysync_responder.go index 29f1470..e94ff5f 100644 --- a/keysync_responder.go +++ b/keysync_responder.go @@ -9,7 +9,6 @@ import ( "io" "net/http" "strings" - "time" "github.com/hf/nitrite" "golang.org/x/crypto/nacl/box" @@ -26,8 +25,6 @@ var ( errPCRNotIdentical = errors.New("remote enclave's PCR values not identical") ) -type timeFunc func() time.Time - // nonceHandler returns a HandlerFunc that creates a new nonce and returns it // to the client. func nonceHandler(e *Enclave) http.HandlerFunc { @@ -45,7 +42,7 @@ func nonceHandler(e *Enclave) http.HandlerFunc { // respSyncHandler returns a HandlerFunc that shares our secret key material // with the requesting enclave -- after authentication, of course. -func respSyncHandler(e *Enclave, curTime timeFunc) http.HandlerFunc { +func respSyncHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ourNonce, theirNonce nonce diff --git a/keysync_responder_test.go b/keysync_responder_test.go index 2414157..beadeb2 100644 --- a/keysync_responder_test.go +++ b/keysync_responder_test.go @@ -77,11 +77,11 @@ func TestRespSyncHandlerForBadReqs(t *testing.T) { enclave := createEnclave() // Send non-Base64 bogus data. - res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, strings.NewReader("foobar!")) + res = queryHandler(respSyncHandler(enclave), pathSync, strings.NewReader("foobar!")) expect(t, res, http.StatusInternalServerError, errNoBase64.Error()) // Send Base64-encoded bogus data. - res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, strings.NewReader("Zm9vYmFyCg==")) + res = queryHandler(respSyncHandler(enclave), pathSync, strings.NewReader("Zm9vYmFyCg==")) expect(t, res, http.StatusUnauthorized, errFailedVerify.Error()) } @@ -96,7 +96,7 @@ func TestRespSyncHandler(t *testing.T) { } currentTime = func() time.Time { return initAttInfo.attDocTime } - res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, strings.NewReader(initAttInfo.attDoc)) + res = queryHandler(respSyncHandler(enclave), pathSync, strings.NewReader(initAttInfo.attDoc)) // On a non-enclave platform, the responder code will get as far as to // request its attestation document. expect(t, res, http.StatusInternalServerError, errFailedAttestation) @@ -109,7 +109,7 @@ func TestRespSyncHandlerDoS(t *testing.T) { // Send more data than the handler should be willing to read. maxSize := base64.StdEncoding.EncodedLen(maxAttDocLen) body := make([]byte, maxSize+1) - res = queryHandler(respSyncHandler(enclave, time.Now), pathSync, bytes.NewReader(body)) + res = queryHandler(respSyncHandler(enclave), pathSync, bytes.NewReader(body)) expect(t, res, http.StatusInternalServerError, errFailedRespBody.Error()) } From 9edb2c47fd52754ec506816206491740d9629077 Mon Sep 17 00:00:00 2001 From: Philipp Winter Date: Tue, 24 Jan 2023 08:05:34 -0600 Subject: [PATCH 55/55] Be explicit about enclave-internal endpoints. --- handlers.go | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/handlers.go b/handlers.go index 12b4e8f..eb46930 100644 --- a/handlers.go +++ b/handlers.go @@ -44,10 +44,21 @@ func rootHandler(cfg *Config) http.HandlerFunc { } } +// proxyHandler returns an HTTP handler that proxies HTTP requests to the +// enclave-internal HTTP server of our enclave application. +func proxyHandler(e *Enclave) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + e.revProxy.ServeHTTP(w, r) + } +} + // reqSyncHandler returns a handler that lets the enclave application request // state synchronization, which copies the given remote enclave's state into // our state. // +// This is an enclave-internal endpoint that can only be accessed by the +// trusted enclave application. +// // FIXME: https://github.com/brave/nitriding/issues/44 func reqSyncHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -77,6 +88,9 @@ func reqSyncHandler(e *Enclave) http.HandlerFunc { // getStateHandler returns a handler that lets the enclave application retrieve // previously-set state. +// +// This is an enclave-internal endpoint that can only be accessed by the +// trusted enclave application. func getStateHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/octet-stream") @@ -101,6 +115,9 @@ func getStateHandler(e *Enclave) http.HandlerFunc { // putStateHandler returns a handler that lets the enclave application set // state that's synchronized with another enclave in case of horizontal // scaling. The state can be arbitrary bytes. +// +// This is an enclave-internal endpoint that can only be accessed by the +// trusted enclave application. func putStateHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(newLimitReader(r.Body, maxKeyMaterialLen)) @@ -113,19 +130,14 @@ func putStateHandler(e *Enclave) http.HandlerFunc { } } -// proxyHandler returns an HTTP handler that proxies HTTP requests to the -// enclave-internal HTTP server of our enclave application. -func proxyHandler(e *Enclave) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - e.revProxy.ServeHTTP(w, r) - } -} - // hashHandler returns an HTTP handler that allows the enclave application to // register a hash over a public key which is going to be included in // attestation documents. This allows clients to tie the attestation document // (which acts as the root of trust) to key material that's used by the enclave // application. +// +// This is an enclave-internal endpoint that can only be accessed by the +// trusted enclave application. func hashHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // Allow an extra byte for the \n. @@ -161,6 +173,9 @@ func hashHandler(e *Enclave) http.HandlerFunc { // that state synchronization among enclaves does not work until the // application signalled its readiness. While not ideal, we chose to ignore // this for now. +// +// This is an enclave-internal endpoint that can only be accessed by the +// trusted enclave application. func readyHandler(e *Enclave) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { close(e.ready)