maintain (dep): Bump golang.org/x/crypto from 0.0.0-20220131195533-30dcbda58838 to 0.1.0 (#572)

Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.0.0-20220131195533-30dcbda58838 to 0.1.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/commits/v0.1.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
dependabot[bot] 2023-03-14 00:41:00 +11:00 committed by GitHub
parent b3d1e8681b
commit 88412fb13f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
278 changed files with 21070 additions and 7727 deletions

6
go.mod
View file

@ -33,11 +33,11 @@ require (
github.com/tredoe/osutil v1.0.6 github.com/tredoe/osutil v1.0.6
github.com/vmware/go-nfs-client v0.0.0-20190605212624-d43b92724c1b github.com/vmware/go-nfs-client v0.0.0-20190605212624-d43b92724c1b
github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 golang.org/x/crypto v0.1.0
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 golang.org/x/image v0.0.0-20211028202545-6944b10bf410
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 golang.org/x/net v0.1.0
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
google.golang.org/api v0.15.0 google.golang.org/api v0.15.0
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect

36
go.sum
View file

@ -287,6 +287,7 @@ github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0B
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/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= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zeebo/admission/v3 v3.0.3/go.mod h1:2OWyAS5yo0Xvj2AEUosOjTUHxaY0oIIiCrXGKCYzWpo= github.com/zeebo/admission/v3 v3.0.3/go.mod h1:2OWyAS5yo0Xvj2AEUosOjTUHxaY0oIIiCrXGKCYzWpo=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
@ -310,11 +311,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c h1:FRR4fGZm/CMwZka5baQ4z8c8StbxJOMjS/45e0BAxK0=
golang.org/x/image v0.0.0-20210622092929-e6eecd499c2c/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -325,8 +326,9 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/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-20180724234803-3673e40ba225/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-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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -345,13 +347,15 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/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-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-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-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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4 h1:DZshvxDdVoeKIbudAdFEKi+f70l51luSy/7b76ibTY0=
golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -367,8 +371,9 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20190911185100-cd5d95a43a6e/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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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/sys v0.0.0-20180830151530-49385e6e1522/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-20180909124046-d0be0721c37e/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-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -395,16 +400,23 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20211007075335-d3039528d8ac/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-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= 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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/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.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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
@ -424,12 +436,12 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=

3
vendor/golang.org/x/crypto/AUTHORS generated vendored
View file

@ -1,3 +0,0 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at https://tip.golang.org/AUTHORS.

View file

@ -1,3 +0,0 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at https://tip.golang.org/CONTRIBUTORS.

View file

@ -3,17 +3,20 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package acme provides an implementation of the // Package acme provides an implementation of the
// Automatic Certificate Management Environment (ACME) spec. // Automatic Certificate Management Environment (ACME) spec,
// The initial implementation was based on ACME draft-02 and // most famously used by Let's Encrypt.
// is now being extended to comply with RFC 8555. //
// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 // The initial implementation of this package was based on an early version
// and https://tools.ietf.org/html/rfc8555 for details. // of the spec. The current implementation supports only the modern
// RFC 8555 but some of the old API surface remains for compatibility.
// While code using the old API will still compile, it will return an error.
// Note the deprecation comments to update your code.
//
// See https://tools.ietf.org/html/rfc8555 for the spec.
// //
// Most common scenarios will want to use autocert subdirectory instead, // Most common scenarios will want to use autocert subdirectory instead,
// which provides automatic access to certificates from Let's Encrypt // which provides automatic access to certificates from Let's Encrypt
// and any other ACME-based CA. // and any other ACME-based CA.
//
// This package is a work in progress and makes no API stability promises.
package acme package acme
import ( import (
@ -33,8 +36,6 @@ import (
"encoding/pem" "encoding/pem"
"errors" "errors"
"fmt" "fmt"
"io"
"io/ioutil"
"math/big" "math/big"
"net/http" "net/http"
"strings" "strings"
@ -72,6 +73,7 @@ const (
) )
// Client is an ACME client. // Client is an ACME client.
//
// The only required field is Key. An example of creating a client with a new key // The only required field is Key. An example of creating a client with a new key
// is as follows: // is as follows:
// //
@ -80,7 +82,6 @@ const (
// log.Fatal(err) // log.Fatal(err)
// } // }
// client := &Client{Key: key} // client := &Client{Key: key}
//
type Client struct { type Client struct {
// Key is the account key used to register with a CA and sign requests. // Key is the account key used to register with a CA and sign requests.
// Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey. // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey.
@ -145,9 +146,6 @@ type Client struct {
func (c *Client) accountKID(ctx context.Context) KeyID { func (c *Client) accountKID(ctx context.Context) KeyID {
c.cacheMu.Lock() c.cacheMu.Lock()
defer c.cacheMu.Unlock() defer c.cacheMu.Unlock()
if !c.dir.rfcCompliant() {
return noKeyID
}
if c.KID != noKeyID { if c.KID != noKeyID {
return c.KID return c.KID
} }
@ -159,6 +157,8 @@ func (c *Client) accountKID(ctx context.Context) KeyID {
return c.KID return c.KID
} }
var errPreRFC = errors.New("acme: server does not support the RFC 8555 version of ACME")
// Discover performs ACME server discovery using c.DirectoryURL. // Discover performs ACME server discovery using c.DirectoryURL.
// //
// It caches successful result. So, subsequent calls will not result in // It caches successful result. So, subsequent calls will not result in
@ -179,53 +179,36 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
c.addNonce(res.Header) c.addNonce(res.Header)
var v struct { var v struct {
Reg string `json:"new-reg"` Reg string `json:"newAccount"`
RegRFC string `json:"newAccount"` Authz string `json:"newAuthz"`
Authz string `json:"new-authz"` Order string `json:"newOrder"`
AuthzRFC string `json:"newAuthz"` Revoke string `json:"revokeCert"`
OrderRFC string `json:"newOrder"` Nonce string `json:"newNonce"`
Cert string `json:"new-cert"` KeyChange string `json:"keyChange"`
Revoke string `json:"revoke-cert"`
RevokeRFC string `json:"revokeCert"`
NonceRFC string `json:"newNonce"`
KeyChangeRFC string `json:"keyChange"`
Meta struct { Meta struct {
Terms string `json:"terms-of-service"` Terms string `json:"termsOfService"`
TermsRFC string `json:"termsOfService"` Website string `json:"website"`
WebsiteRFC string `json:"website"` CAA []string `json:"caaIdentities"`
CAA []string `json:"caa-identities"` ExternalAcct bool `json:"externalAccountRequired"`
CAARFC []string `json:"caaIdentities"`
ExternalAcctRFC bool `json:"externalAccountRequired"`
} }
} }
if err := json.NewDecoder(res.Body).Decode(&v); err != nil { if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return Directory{}, err return Directory{}, err
} }
if v.OrderRFC == "" { if v.Order == "" {
// Non-RFC compliant ACME CA. return Directory{}, errPreRFC
}
c.dir = &Directory{ c.dir = &Directory{
RegURL: v.Reg, RegURL: v.Reg,
AuthzURL: v.Authz, AuthzURL: v.Authz,
CertURL: v.Cert, OrderURL: v.Order,
RevokeURL: v.Revoke, RevokeURL: v.Revoke,
NonceURL: v.Nonce,
KeyChangeURL: v.KeyChange,
Terms: v.Meta.Terms, Terms: v.Meta.Terms,
Website: v.Meta.WebsiteRFC, Website: v.Meta.Website,
CAA: v.Meta.CAA, CAA: v.Meta.CAA,
} ExternalAccountRequired: v.Meta.ExternalAcct,
return *c.dir, nil
}
// RFC compliant ACME CA.
c.dir = &Directory{
RegURL: v.RegRFC,
AuthzURL: v.AuthzRFC,
OrderURL: v.OrderRFC,
RevokeURL: v.RevokeRFC,
NonceURL: v.NonceRFC,
KeyChangeURL: v.KeyChangeRFC,
Terms: v.Meta.TermsRFC,
Website: v.Meta.WebsiteRFC,
CAA: v.Meta.CAARFC,
ExternalAccountRequired: v.Meta.ExternalAcctRFC,
} }
return *c.dir, nil return *c.dir, nil
} }
@ -237,55 +220,11 @@ func (c *Client) directoryURL() string {
return LetsEncryptURL return LetsEncryptURL
} }
// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format. // CreateCert was part of the old version of ACME. It is incompatible with RFC 8555.
// It is incompatible with RFC 8555. Callers should use CreateOrderCert when interfacing
// with an RFC-compliant CA.
// //
// The exp argument indicates the desired certificate validity duration. CA may issue a certificate // Deprecated: this was for the pre-RFC 8555 version of ACME. Callers should use CreateOrderCert.
// with a different duration.
// If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain.
//
// In the case where CA server does not provide the issued certificate in the response,
// CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips.
// In such a scenario, the caller can cancel the polling with ctx.
//
// CreateCert returns an error if the CA's response or chain was unreasonably large.
// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) { func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) {
if _, err := c.Discover(ctx); err != nil { return nil, "", errPreRFC
return nil, "", err
}
req := struct {
Resource string `json:"resource"`
CSR string `json:"csr"`
NotBefore string `json:"notBefore,omitempty"`
NotAfter string `json:"notAfter,omitempty"`
}{
Resource: "new-cert",
CSR: base64.RawURLEncoding.EncodeToString(csr),
}
now := timeNow()
req.NotBefore = now.Format(time.RFC3339)
if exp > 0 {
req.NotAfter = now.Add(exp).Format(time.RFC3339)
}
res, err := c.post(ctx, nil, c.dir.CertURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, "", err
}
defer res.Body.Close()
curl := res.Header.Get("Location") // cert permanent URL
if res.ContentLength == 0 {
// no cert in the body; poll until we get it
cert, err := c.FetchCert(ctx, curl, bundle)
return cert, curl, err
}
// slurp issued cert and CA chain, if requested
cert, err := c.responseCert(ctx, res, bundle)
return cert, curl, err
} }
// FetchCert retrieves already issued certificate from the given url, in DER format. // FetchCert retrieves already issued certificate from the given url, in DER format.
@ -299,22 +238,12 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
// Callers are encouraged to parse the returned value to ensure the certificate is valid // Callers are encouraged to parse the returned value to ensure the certificate is valid
// and has expected features. // and has expected features.
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) { func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
dir, err := c.Discover(ctx) if _, err := c.Discover(ctx); err != nil {
if err != nil {
return nil, err return nil, err
} }
if dir.rfcCompliant() {
return c.fetchCertRFC(ctx, url, bundle) return c.fetchCertRFC(ctx, url, bundle)
} }
// Legacy non-authenticated GET request.
res, err := c.get(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
return c.responseCert(ctx, res, bundle)
}
// RevokeCert revokes a previously issued certificate cert, provided in DER format. // RevokeCert revokes a previously issued certificate cert, provided in DER format.
// //
// The key argument, used to sign the request, must be authorized // The key argument, used to sign the request, must be authorized
@ -322,32 +251,12 @@ func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]by
// For instance, the key pair of the certificate may be authorized. // For instance, the key pair of the certificate may be authorized.
// If the key is nil, c.Key is used instead. // If the key is nil, c.Key is used instead.
func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error { func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
dir, err := c.Discover(ctx) if _, err := c.Discover(ctx); err != nil {
if err != nil {
return err return err
} }
if dir.rfcCompliant() {
return c.revokeCertRFC(ctx, key, cert, reason) return c.revokeCertRFC(ctx, key, cert, reason)
} }
// Legacy CA.
body := &struct {
Resource string `json:"resource"`
Cert string `json:"certificate"`
Reason int `json:"reason"`
}{
Resource: "revoke-cert",
Cert: base64.RawURLEncoding.EncodeToString(cert),
Reason: int(reason),
}
res, err := c.post(ctx, key, dir.RevokeURL, body, wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
return nil
}
// AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service // AcceptTOS always returns true to indicate the acceptance of a CA's Terms of Service
// during account registration. See Register method of Client for more details. // during account registration. See Register method of Client for more details.
func AcceptTOS(tosURL string) bool { return true } func AcceptTOS(tosURL string) bool { return true }
@ -368,75 +277,47 @@ func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL
if c.Key == nil { if c.Key == nil {
return nil, errors.New("acme: client.Key must be set to Register") return nil, errors.New("acme: client.Key must be set to Register")
} }
if _, err := c.Discover(ctx); err != nil {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err return nil, err
} }
if dir.rfcCompliant() {
return c.registerRFC(ctx, acct, prompt) return c.registerRFC(ctx, acct, prompt)
} }
// Legacy ACME draft registration flow.
a, err := c.doReg(ctx, dir.RegURL, "new-reg", acct)
if err != nil {
return nil, err
}
var accept bool
if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms {
accept = prompt(a.CurrentTerms)
}
if accept {
a.AgreedTerms = a.CurrentTerms
a, err = c.UpdateReg(ctx, a)
}
return a, err
}
// GetReg retrieves an existing account associated with c.Key. // GetReg retrieves an existing account associated with c.Key.
// //
// The url argument is an Account URI used with pre-RFC 8555 CAs. // The url argument is a legacy artifact of the pre-RFC 8555 API
// It is ignored when interfacing with an RFC-compliant CA. // and is ignored.
func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) {
dir, err := c.Discover(ctx) if _, err := c.Discover(ctx); err != nil {
if err != nil {
return nil, err return nil, err
} }
if dir.rfcCompliant() {
return c.getRegRFC(ctx) return c.getRegRFC(ctx)
} }
// Legacy CA.
a, err := c.doReg(ctx, url, "reg", nil)
if err != nil {
return nil, err
}
a.URI = url
return a, nil
}
// UpdateReg updates an existing registration. // UpdateReg updates an existing registration.
// It returns an updated account copy. The provided account is not modified. // It returns an updated account copy. The provided account is not modified.
// //
// When interfacing with RFC-compliant CAs, a.URI is ignored and the account URL // The account's URI is ignored and the account URL associated with
// associated with c.Key is used instead. // c.Key is used instead.
func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error) { func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error) {
dir, err := c.Discover(ctx) if _, err := c.Discover(ctx); err != nil {
if err != nil {
return nil, err return nil, err
} }
if dir.rfcCompliant() {
return c.updateRegRFC(ctx, acct) return c.updateRegRFC(ctx, acct)
} }
// Legacy CA. // AccountKeyRollover attempts to transition a client's account key to a new key.
uri := acct.URI // On success client's Key is updated which is not concurrency safe.
a, err := c.doReg(ctx, uri, "reg", acct) // On failure an error will be returned.
if err != nil { // The new key is already registered with the ACME provider if the following is true:
return nil, err // - error is of type acme.Error
} // - StatusCode should be 409 (Conflict)
a.URI = uri // - Location header will have the KID of the associated account
return a, nil //
// More about account key rollover can be found at
// https://tools.ietf.org/html/rfc8555#section-7.3.5.
func (c *Client) AccountKeyRollover(ctx context.Context, newKey crypto.Signer) error {
return c.accountKeyRollover(ctx, newKey)
} }
// Authorize performs the initial step in the pre-authorization flow, // Authorize performs the initial step in the pre-authorization flow,
@ -505,17 +386,11 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization
// If a caller needs to poll an authorization until its status is final, // If a caller needs to poll an authorization until its status is final,
// see the WaitAuthorization method. // see the WaitAuthorization method.
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) { func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
dir, err := c.Discover(ctx) if _, err := c.Discover(ctx); err != nil {
if err != nil {
return nil, err return nil, err
} }
var res *http.Response res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if dir.rfcCompliant() {
res, err = c.postAsGet(ctx, url, wantStatus(http.StatusOK))
} else {
res, err = c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -537,7 +412,6 @@ func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorizati
// //
// It does not revoke existing certificates. // It does not revoke existing certificates.
func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
// Required for c.accountKID() when in RFC mode.
if _, err := c.Discover(ctx); err != nil { if _, err := c.Discover(ctx); err != nil {
return err return err
} }
@ -567,18 +441,11 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
// In all other cases WaitAuthorization returns an error. // In all other cases WaitAuthorization returns an error.
// If the Status is StatusInvalid, the returned error is of type *AuthorizationError. // If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) { func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
// Required for c.accountKID() when in RFC mode. if _, err := c.Discover(ctx); err != nil {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err return nil, err
} }
getfn := c.postAsGet
if !dir.rfcCompliant() {
getfn = c.get
}
for { for {
res, err := getfn(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -621,17 +488,11 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
// //
// A client typically polls a challenge status using this method. // A client typically polls a challenge status using this method.
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) { func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
// Required for c.accountKID() when in RFC mode. if _, err := c.Discover(ctx); err != nil {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err return nil, err
} }
getfn := c.postAsGet res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if !dir.rfcCompliant() {
getfn = c.get
}
res, err := getfn(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -649,29 +510,11 @@ func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, erro
// //
// The server will then perform the validation asynchronously. // The server will then perform the validation asynchronously.
func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) { func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) {
// Required for c.accountKID() when in RFC mode. if _, err := c.Discover(ctx); err != nil {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err return nil, err
} }
var req interface{} = json.RawMessage("{}") // RFC-compliant CA res, err := c.post(ctx, nil, chal.URI, json.RawMessage("{}"), wantStatus(
if !dir.rfcCompliant() {
auth, err := keyAuth(c.Key.Public(), chal.Token)
if err != nil {
return nil, err
}
req = struct {
Resource string `json:"resource"`
Type string `json:"type"`
Auth string `json:"keyAuthorization"`
}{
Resource: "challenge",
Type: chal.Type,
Auth: auth,
}
}
res, err := c.post(ctx, nil, chal.URI, req, wantStatus(
http.StatusOK, // according to the spec http.StatusOK, // according to the spec
http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md) http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
)) ))
@ -722,7 +565,7 @@ func (c *Client) HTTP01ChallengePath(token string) string {
// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response. // TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
// //
// Deprecated: This challenge type is unused in both draft-02 and RFC versions of ACME spec. // Deprecated: This challenge type is unused in both draft-02 and RFC versions of the ACME spec.
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
ka, err := keyAuth(c.Key.Public(), token) ka, err := keyAuth(c.Key.Public(), token)
if err != nil { if err != nil {
@ -740,7 +583,7 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl
// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response. // TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
// //
// Deprecated: This challenge type is unused in both draft-02 and RFC versions of ACME spec. // Deprecated: This challenge type is unused in both draft-02 and RFC versions of the ACME spec.
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
b := sha256.Sum256([]byte(token)) b := sha256.Sum256([]byte(token))
h := hex.EncodeToString(b[:]) h := hex.EncodeToString(b[:])
@ -807,63 +650,6 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption)
return tlsChallengeCert([]string{domain}, newOpt) return tlsChallengeCert([]string{domain}, newOpt)
} }
// doReg sends all types of registration requests the old way (pre-RFC world).
// The type of request is identified by typ argument, which is a "resource"
// in the ACME spec terms.
//
// A non-nil acct argument indicates whether the intention is to mutate data
// of the Account. Only Contact and Agreement of its fields are used
// in such cases.
func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Account) (*Account, error) {
req := struct {
Resource string `json:"resource"`
Contact []string `json:"contact,omitempty"`
Agreement string `json:"agreement,omitempty"`
}{
Resource: typ,
}
if acct != nil {
req.Contact = acct.Contact
req.Agreement = acct.AgreedTerms
}
res, err := c.post(ctx, nil, url, req, wantStatus(
http.StatusOK, // updates and deletes
http.StatusCreated, // new account creation
http.StatusAccepted, // Let's Encrypt divergent implementation
))
if err != nil {
return nil, err
}
defer res.Body.Close()
var v struct {
Contact []string
Agreement string
Authorizations string
Certificates string
}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid response: %v", err)
}
var tos string
if v := linkHeader(res.Header, "terms-of-service"); len(v) > 0 {
tos = v[0]
}
var authz string
if v := linkHeader(res.Header, "next"); len(v) > 0 {
authz = v[0]
}
return &Account{
URI: res.Header.Get("Location"),
Contact: v.Contact,
AgreedTerms: v.Agreement,
CurrentTerms: tos,
Authz: authz,
Authorizations: v.Authorizations,
Certificates: v.Certificates,
}, nil
}
// popNonce returns a nonce value previously stored with c.addNonce // popNonce returns a nonce value previously stored with c.addNonce
// or fetches a fresh one from c.dir.NonceURL. // or fetches a fresh one from c.dir.NonceURL.
// If NonceURL is empty, it first tries c.directoryURL() and, failing that, // If NonceURL is empty, it first tries c.directoryURL() and, failing that,
@ -938,78 +724,6 @@ func nonceFromHeader(h http.Header) string {
return h.Get("Replay-Nonce") return h.Get("Replay-Nonce")
} }
func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) {
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
if err != nil {
return nil, fmt.Errorf("acme: response stream: %v", err)
}
if len(b) > maxCertSize {
return nil, errors.New("acme: certificate is too big")
}
cert := [][]byte{b}
if !bundle {
return cert, nil
}
// Append CA chain cert(s).
// At least one is required according to the spec:
// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-6.3.1
up := linkHeader(res.Header, "up")
if len(up) == 0 {
return nil, errors.New("acme: rel=up link not found")
}
if len(up) > maxChainLen {
return nil, errors.New("acme: rel=up link is too large")
}
for _, url := range up {
cc, err := c.chainCert(ctx, url, 0)
if err != nil {
return nil, err
}
cert = append(cert, cc...)
}
return cert, nil
}
// chainCert fetches CA certificate chain recursively by following "up" links.
// Each recursive call increments the depth by 1, resulting in an error
// if the recursion level reaches maxChainLen.
//
// First chainCert call starts with depth of 0.
func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) {
if depth >= maxChainLen {
return nil, errors.New("acme: certificate chain is too deep")
}
res, err := c.get(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
if err != nil {
return nil, err
}
if len(b) > maxCertSize {
return nil, errors.New("acme: certificate is too big")
}
chain := [][]byte{b}
uplink := linkHeader(res.Header, "up")
if len(uplink) > maxChainLen {
return nil, errors.New("acme: certificate chain is too large")
}
for _, up := range uplink {
cc, err := c.chainCert(ctx, up, depth+1)
if err != nil {
return nil, err
}
chain = append(chain, cc...)
}
return chain, nil
}
// linkHeader returns URI-Reference values of all Link headers // linkHeader returns URI-Reference values of all Link headers
// with relation-type rel. // with relation-type rel.
// See https://tools.ietf.org/html/rfc5988#section-5 for details. // See https://tools.ietf.org/html/rfc5988#section-5 for details.
@ -1100,5 +814,5 @@ func encodePEM(typ string, b []byte) []byte {
return pem.EncodeToMemory(pb) return pem.EncodeToMemory(pb)
} }
// timeNow is useful for testing for fixed current time. // timeNow is time.Now, except in tests which can mess with it.
var timeNow = time.Now var timeNow = time.Now

View file

@ -47,6 +47,8 @@ var createCertRetryAfter = time.Minute
// pseudoRand is safe for concurrent use. // pseudoRand is safe for concurrent use.
var pseudoRand *lockedMathRand var pseudoRand *lockedMathRand
var errPreRFC = errors.New("autocert: ACME server doesn't support RFC 8555")
func init() { func init() {
src := mathrand.NewSource(time.Now().UnixNano()) src := mathrand.NewSource(time.Now().UnixNano())
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)} pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
@ -168,6 +170,11 @@ type Manager struct {
// in the template's ExtraExtensions field as is. // in the template's ExtraExtensions field as is.
ExtraExtensions []pkix.Extension ExtraExtensions []pkix.Extension
// ExternalAccountBinding optionally represents an arbitrary binding to an
// account of the CA to which the ACME server is tied.
// See RFC 8555, Section 7.3.4 for more details.
ExternalAccountBinding *acme.ExternalAccountBinding
clientMu sync.Mutex clientMu sync.Mutex
client *acme.Client // initialized by acmeClient method client *acme.Client // initialized by acmeClient method
@ -456,7 +463,7 @@ func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error
leaf: cert.Leaf, leaf: cert.Leaf,
} }
m.state[ck] = s m.state[ck] = s
go m.renew(ck, s.key, s.leaf.NotAfter) m.startRenew(ck, s.key, s.leaf.NotAfter)
return cert, nil return cert, nil
} }
@ -582,8 +589,9 @@ func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate,
if err != nil { if err != nil {
// Remove the failed state after some time, // Remove the failed state after some time,
// making the manager call createCert again on the following TLS hello. // making the manager call createCert again on the following TLS hello.
didRemove := testDidRemoveState // The lifetime of this timer is untracked, so copy mutable local state to avoid races.
time.AfterFunc(createCertRetryAfter, func() { time.AfterFunc(createCertRetryAfter, func() {
defer testDidRemoveState(ck) defer didRemove(ck)
m.stateMu.Lock() m.stateMu.Lock()
defer m.stateMu.Unlock() defer m.stateMu.Unlock()
// Verify the state hasn't changed and it's still invalid // Verify the state hasn't changed and it's still invalid
@ -601,7 +609,7 @@ func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate,
} }
state.cert = der state.cert = der
state.leaf = leaf state.leaf = leaf
go m.renew(ck, state.key, state.leaf.NotAfter) m.startRenew(ck, state.key, state.leaf.NotAfter)
return state.tlscert() return state.tlscert()
} }
@ -658,31 +666,19 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck cert
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if dir.OrderURL == "" {
return nil, nil, errPreRFC
}
var chain [][]byte
switch {
// Pre-RFC legacy CA.
case dir.OrderURL == "":
if err := m.verify(ctx, client, ck.domain); err != nil {
return nil, nil, err
}
der, _, err := client.CreateCert(ctx, csr, 0, true)
if err != nil {
return nil, nil, err
}
chain = der
// RFC 8555 compliant CA.
default:
o, err := m.verifyRFC(ctx, client, ck.domain) o, err := m.verifyRFC(ctx, client, ck.domain)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
der, _, err := client.CreateOrderCert(ctx, o.FinalizeURL, csr, true) chain, _, err := client.CreateOrderCert(ctx, o.FinalizeURL, csr, true)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
chain = der
}
leaf, err = validCert(ck, chain, key, m.now()) leaf, err = validCert(ck, chain, key, m.now())
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -690,69 +686,6 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck cert
return chain, leaf, nil return chain, leaf, nil
} }
// verify runs the identifier (domain) pre-authorization flow for legacy CAs
// using each applicable ACME challenge type.
func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
// Remove all hanging authorizations to reduce rate limit quotas
// after we're done.
var authzURLs []string
defer func() {
go m.deactivatePendingAuthz(authzURLs)
}()
// errs accumulates challenge failure errors, printed if all fail
errs := make(map[*acme.Challenge]error)
challengeTypes := m.supportedChallengeTypes()
var nextTyp int // challengeType index of the next challenge type to try
for {
// Start domain authorization and get the challenge.
authz, err := client.Authorize(ctx, domain)
if err != nil {
return err
}
authzURLs = append(authzURLs, authz.URI)
// No point in accepting challenges if the authorization status
// is in a final state.
switch authz.Status {
case acme.StatusValid:
return nil // already authorized
case acme.StatusInvalid:
return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI)
}
// Pick the next preferred challenge.
var chal *acme.Challenge
for chal == nil && nextTyp < len(challengeTypes) {
chal = pickChallenge(challengeTypes[nextTyp], authz.Challenges)
nextTyp++
}
if chal == nil {
errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain)
for chal, err := range errs {
errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err)
}
return errors.New(errorMsg)
}
cleanup, err := m.fulfill(ctx, client, chal, domain)
if err != nil {
errs[chal] = err
continue
}
defer cleanup()
if _, err := client.Accept(ctx, chal); err != nil {
errs[chal] = err
continue
}
// A challenge is fulfilled and accepted: wait for the CA to validate.
if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil {
errs[chal] = err
continue
}
return nil
}
}
// verifyRFC runs the identifier (domain) order-based authorization flow for RFC compliant CAs // verifyRFC runs the identifier (domain) order-based authorization flow for RFC compliant CAs
// using each applicable ACME challenge type. // using each applicable ACME challenge type.
func (m *Manager) verifyRFC(ctx context.Context, client *acme.Client, domain string) (*acme.Order, error) { func (m *Manager) verifyRFC(ctx context.Context, client *acme.Client, domain string) (*acme.Order, error) {
@ -966,7 +899,7 @@ func httpTokenCacheKey(tokenPath string) string {
return path.Base(tokenPath) + "+http-01" return path.Base(tokenPath) + "+http-01"
} }
// renew starts a cert renewal timer loop, one per domain. // startRenew starts a cert renewal timer loop, one per domain.
// //
// The loop is scheduled in two cases: // The loop is scheduled in two cases:
// - a cert was fetched from cache for the first time (wasn't in m.state) // - a cert was fetched from cache for the first time (wasn't in m.state)
@ -974,7 +907,7 @@ func httpTokenCacheKey(tokenPath string) string {
// //
// The key argument is a certificate private key. // The key argument is a certificate private key.
// The exp argument is the cert expiration time (NotAfter). // The exp argument is the cert expiration time (NotAfter).
func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) { func (m *Manager) startRenew(ck certKey, key crypto.Signer, exp time.Time) {
m.renewalMu.Lock() m.renewalMu.Lock()
defer m.renewalMu.Unlock() defer m.renewalMu.Unlock()
if m.renewal[ck] != nil { if m.renewal[ck] != nil {
@ -1068,7 +1001,7 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
if m.Email != "" { if m.Email != "" {
contact = []string{"mailto:" + m.Email} contact = []string{"mailto:" + m.Email}
} }
a := &acme.Account{Contact: contact} a := &acme.Account{Contact: contact, ExternalAccountBinding: m.ExternalAccountBinding}
_, err := client.Register(ctx, a, m.Prompt) _, err := client.Register(ctx, a, m.Prompt)
if err == nil || isAccountAlreadyExist(err) { if err == nil || isAccountAlreadyExist(err) {
m.client = client m.client = client

View file

@ -7,7 +7,6 @@ package autocert
import ( import (
"context" "context"
"errors" "errors"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
) )
@ -41,14 +40,14 @@ type DirCache string
// Get reads a certificate data from the specified file name. // Get reads a certificate data from the specified file name.
func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) { func (d DirCache) Get(ctx context.Context, name string) ([]byte, error) {
name = filepath.Join(string(d), name) name = filepath.Join(string(d), filepath.Clean("/"+name))
var ( var (
data []byte data []byte
err error err error
done = make(chan struct{}) done = make(chan struct{})
) )
go func() { go func() {
data, err = ioutil.ReadFile(name) data, err = os.ReadFile(name)
close(done) close(done)
}() }()
select { select {
@ -82,7 +81,7 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
case <-ctx.Done(): case <-ctx.Done():
// Don't overwrite the file if the context was canceled. // Don't overwrite the file if the context was canceled.
default: default:
newName := filepath.Join(string(d), name) newName := filepath.Join(string(d), filepath.Clean("/"+name))
err = os.Rename(tmp, newName) err = os.Rename(tmp, newName)
} }
}() }()
@ -96,7 +95,7 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
// Delete removes the specified file name. // Delete removes the specified file name.
func (d DirCache) Delete(ctx context.Context, name string) error { func (d DirCache) Delete(ctx context.Context, name string) error {
name = filepath.Join(string(d), name) name = filepath.Join(string(d), filepath.Clean("/"+name))
var ( var (
err error err error
done = make(chan struct{}) done = make(chan struct{})
@ -119,7 +118,7 @@ func (d DirCache) Delete(ctx context.Context, name string) error {
// writeTempFile writes b to a temporary file, closes the file and returns its path. // writeTempFile writes b to a temporary file, closes the file and returns its path.
func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) { func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) {
// TempFile uses 0600 permissions // TempFile uses 0600 permissions
f, err := ioutil.TempFile(string(d), prefix) f, err := os.CreateTemp(string(d), prefix)
if err != nil { if err != nil {
return "", err return "", err
} }

View file

@ -23,6 +23,7 @@ type domainRenewal struct {
timerMu sync.Mutex timerMu sync.Mutex
timer *time.Timer timer *time.Timer
timerClose chan struct{} // if non-nil, renew closes this channel (and nils out the timer fields) instead of running
} }
// start starts a cert renewal timer at the time // start starts a cert renewal timer at the time
@ -38,16 +39,28 @@ func (dr *domainRenewal) start(exp time.Time) {
dr.timer = time.AfterFunc(dr.next(exp), dr.renew) dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
} }
// stop stops the cert renewal timer. // stop stops the cert renewal timer and waits for any in-flight calls to renew
// If the timer is already stopped, calling stop is a noop. // to complete. If the timer is already stopped, calling stop is a noop.
func (dr *domainRenewal) stop() { func (dr *domainRenewal) stop() {
dr.timerMu.Lock() dr.timerMu.Lock()
defer dr.timerMu.Unlock() defer dr.timerMu.Unlock()
for {
if dr.timer == nil { if dr.timer == nil {
return return
} }
dr.timer.Stop() if dr.timer.Stop() {
dr.timer = nil dr.timer = nil
return
} else {
// dr.timer fired, and we acquired dr.timerMu before the renew callback did.
// (We know this because otherwise the renew callback would have reset dr.timer!)
timerClose := make(chan struct{})
dr.timerClose = timerClose
dr.timerMu.Unlock()
<-timerClose
dr.timerMu.Lock()
}
}
} }
// renew is called periodically by a timer. // renew is called periodically by a timer.
@ -55,7 +68,9 @@ func (dr *domainRenewal) stop() {
func (dr *domainRenewal) renew() { func (dr *domainRenewal) renew() {
dr.timerMu.Lock() dr.timerMu.Lock()
defer dr.timerMu.Unlock() defer dr.timerMu.Unlock()
if dr.timer == nil { if dr.timerClose != nil {
close(dr.timerClose)
dr.timer, dr.timerClose = nil, nil
return return
} }
@ -67,8 +82,8 @@ func (dr *domainRenewal) renew() {
next = renewJitter / 2 next = renewJitter / 2
next += time.Duration(pseudoRand.int63n(int64(next))) next += time.Duration(pseudoRand.int63n(int64(next)))
} }
dr.timer = time.AfterFunc(next, dr.renew)
testDidRenewLoop(next, err) testDidRenewLoop(next, err)
dr.timer = time.AfterFunc(next, dr.renew)
} }
// updateState locks and replaces the relevant Manager.state item with the given // updateState locks and replaces the relevant Manager.state item with the given

View file

@ -12,7 +12,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io"
"math/big" "math/big"
"net/http" "net/http"
"strconv" "strconv"
@ -310,7 +310,7 @@ func isRetriable(code int) bool {
func responseError(resp *http.Response) error { func responseError(resp *http.Response) error {
// don't care if ReadAll returns an error: // don't care if ReadAll returns an error:
// json.Unmarshal will fail in that case anyway // json.Unmarshal will fail in that case anyway
b, _ := ioutil.ReadAll(resp.Body) b, _ := io.ReadAll(resp.Body)
e := &wireError{Status: resp.StatusCode} e := &wireError{Status: resp.StatusCode}
if err := json.Unmarshal(b, e); err != nil { if err := json.Unmarshal(b, e); err != nil {
// this is not a regular error response: // this is not a regular error response:

View file

@ -33,6 +33,10 @@ const noKeyID = KeyID("")
// See https://tools.ietf.org/html/rfc8555#section-6.3 for more details. // See https://tools.ietf.org/html/rfc8555#section-6.3 for more details.
const noPayload = "" const noPayload = ""
// noNonce indicates that the nonce should be omitted from the protected header.
// See jwsEncodeJSON for details.
const noNonce = ""
// jsonWebSignature can be easily serialized into a JWS following // jsonWebSignature can be easily serialized into a JWS following
// https://tools.ietf.org/html/rfc7515#section-3.2. // https://tools.ietf.org/html/rfc7515#section-3.2.
type jsonWebSignature struct { type jsonWebSignature struct {
@ -45,30 +49,54 @@ type jsonWebSignature struct {
// The result is serialized in JSON format containing either kid or jwk // The result is serialized in JSON format containing either kid or jwk
// fields based on the provided KeyID value. // fields based on the provided KeyID value.
// //
// If kid is non-empty, its quoted value is inserted in the protected head // The claimset is marshalled using json.Marshal unless it is a string.
// In which case it is inserted directly into the message.
//
// If kid is non-empty, its quoted value is inserted in the protected header
// as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted // as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted
// as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive. // as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive.
// //
// If nonce is non-empty, its quoted value is inserted in the protected header.
//
// See https://tools.ietf.org/html/rfc7515#section-7. // See https://tools.ietf.org/html/rfc7515#section-7.
func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, url string) ([]byte, error) { func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, url string) ([]byte, error) {
if key == nil {
return nil, errors.New("nil key")
}
alg, sha := jwsHasher(key.Public()) alg, sha := jwsHasher(key.Public())
if alg == "" || !sha.Available() { if alg == "" || !sha.Available() {
return nil, ErrUnsupportedKey return nil, ErrUnsupportedKey
} }
var phead string headers := struct {
Alg string `json:"alg"`
KID string `json:"kid,omitempty"`
JWK json.RawMessage `json:"jwk,omitempty"`
Nonce string `json:"nonce,omitempty"`
URL string `json:"url"`
}{
Alg: alg,
Nonce: nonce,
URL: url,
}
switch kid { switch kid {
case noKeyID: case noKeyID:
jwk, err := jwkEncode(key.Public()) jwk, err := jwkEncode(key.Public())
if err != nil { if err != nil {
return nil, err return nil, err
} }
phead = fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q,"url":%q}`, alg, jwk, nonce, url) headers.JWK = json.RawMessage(jwk)
default: default:
phead = fmt.Sprintf(`{"alg":%q,"kid":%q,"nonce":%q,"url":%q}`, alg, kid, nonce, url) headers.KID = string(kid)
} }
phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) phJSON, err := json.Marshal(headers)
if err != nil {
return nil, err
}
phead := base64.RawURLEncoding.EncodeToString([]byte(phJSON))
var payload string var payload string
if claimset != noPayload { if val, ok := claimset.(string); ok {
payload = val
} else {
cs, err := json.Marshal(claimset) cs, err := json.Marshal(claimset)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -13,7 +13,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"time" "time"
) )
@ -24,6 +23,9 @@ import (
// //
// It only works with CAs implementing RFC 8555. // It only works with CAs implementing RFC 8555.
func (c *Client) DeactivateReg(ctx context.Context) error { func (c *Client) DeactivateReg(ctx context.Context) error {
if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
return err
}
url := string(c.accountKID(ctx)) url := string(c.accountKID(ctx))
if url == "" { if url == "" {
return ErrNoAccount return ErrNoAccount
@ -148,6 +150,42 @@ func responseAccount(res *http.Response) (*Account, error) {
}, nil }, nil
} }
// accountKeyRollover attempts to perform account key rollover.
// On success it will change client.Key to the new key.
func (c *Client) accountKeyRollover(ctx context.Context, newKey crypto.Signer) error {
dir, err := c.Discover(ctx) // Also required by c.accountKID
if err != nil {
return err
}
kid := c.accountKID(ctx)
if kid == noKeyID {
return ErrNoAccount
}
oldKey, err := jwkEncode(c.Key.Public())
if err != nil {
return err
}
payload := struct {
Account string `json:"account"`
OldKey json.RawMessage `json:"oldKey"`
}{
Account: string(kid),
OldKey: json.RawMessage(oldKey),
}
inner, err := jwsEncodeJSON(payload, newKey, noKeyID, noNonce, dir.KeyChangeURL)
if err != nil {
return err
}
res, err := c.post(ctx, nil, dir.KeyChangeURL, base64.RawURLEncoding.EncodeToString(inner), wantStatus(http.StatusOK))
if err != nil {
return err
}
defer res.Body.Close()
c.Key = newKey
return nil
}
// AuthorizeOrder initiates the order-based application for certificate issuance, // AuthorizeOrder initiates the order-based application for certificate issuance,
// as opposed to pre-authorization in Authorize. // as opposed to pre-authorization in Authorize.
// It is only supported by CAs implementing RFC 8555. // It is only supported by CAs implementing RFC 8555.
@ -351,7 +389,7 @@ func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][
// Get all the bytes up to a sane maximum. // Get all the bytes up to a sane maximum.
// Account very roughly for base64 overhead. // Account very roughly for base64 overhead.
const max = maxCertChainSize + maxCertChainSize/33 const max = maxCertChainSize + maxCertChainSize/33
b, err := ioutil.ReadAll(io.LimitReader(res.Body, max+1)) b, err := io.ReadAll(io.LimitReader(res.Body, max+1))
if err != nil { if err != nil {
return nil, fmt.Errorf("acme: fetch cert response stream: %v", err) return nil, fmt.Errorf("acme: fetch cert response stream: %v", err)
} }
@ -430,7 +468,7 @@ func (c *Client) ListCertAlternates(ctx context.Context, url string) ([]string,
// We don't need the body but we need to discard it so we don't end up // We don't need the body but we need to discard it so we don't end up
// preventing keep-alive // preventing keep-alive
if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { if _, err := io.Copy(io.Discard, res.Body); err != nil {
return nil, fmt.Errorf("acme: cert alternates response stream: %v", err) return nil, fmt.Errorf("acme: cert alternates response stream: %v", err)
} }
alts := linkHeader(res.Header, "alternate") alts := linkHeader(res.Header, "alternate")

View file

@ -305,14 +305,6 @@ type Directory struct {
ExternalAccountRequired bool ExternalAccountRequired bool
} }
// rfcCompliant reports whether the ACME server implements RFC 8555.
// Note that some servers may have incomplete RFC implementation
// even if the returned value is true.
// If rfcCompliant reports false, the server most likely implements draft-02.
func (d *Directory) rfcCompliant() bool {
return d.OrderURL != ""
}
// Order represents a client's request for a certificate. // Order represents a client's request for a certificate.
// It tracks the request flow progress through to issuance. // It tracks the request flow progress through to issuance.
type Order struct { type Order struct {

View file

@ -11,8 +11,7 @@
// If you aren't sure which function you need, use Argon2id (IDKey) and // If you aren't sure which function you need, use Argon2id (IDKey) and
// the parameter recommendations for your scenario. // the parameter recommendations for your scenario.
// //
// // # Argon2i
// Argon2i
// //
// Argon2i (implemented by Key) is the side-channel resistant version of Argon2. // Argon2i (implemented by Key) is the side-channel resistant version of Argon2.
// It uses data-independent memory access, which is preferred for password // It uses data-independent memory access, which is preferred for password
@ -21,8 +20,7 @@
// parameters (taken from [2]) for non-interactive operations are time=3 and to // parameters (taken from [2]) for non-interactive operations are time=3 and to
// use the maximum available memory. // use the maximum available memory.
// //
// // # Argon2id
// Argon2id
// //
// Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining // Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining
// Argon2i and Argon2d. It uses data-independent memory access for the first // Argon2i and Argon2d. It uses data-independent memory access for the first

View file

@ -12,7 +12,7 @@ import (
"errors" "errors"
"math/bits" "math/bits"
"golang.org/x/crypto/internal/subtle" "golang.org/x/crypto/internal/alias"
) )
const ( const (
@ -189,7 +189,7 @@ func (s *Cipher) XORKeyStream(dst, src []byte) {
panic("chacha20: output smaller than input") panic("chacha20: output smaller than input")
} }
dst = dst[:len(src)] dst = dst[:len(src)]
if subtle.InexactOverlap(dst, src) { if alias.InexactOverlap(dst, src) {
panic("chacha20: invalid buffer overlap") panic("chacha20: invalid buffer overlap")
} }

View file

@ -15,6 +15,7 @@ const bufSize = 256
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only // xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
// be called when the vector facility is available. Implementation in asm_s390x.s. // be called when the vector facility is available. Implementation in asm_s390x.s.
//
//go:noescape //go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)

View file

@ -9,7 +9,8 @@ package curve25519 // import "golang.org/x/crypto/curve25519"
import ( import (
"crypto/subtle" "crypto/subtle"
"fmt" "errors"
"strconv"
"golang.org/x/crypto/curve25519/internal/field" "golang.org/x/crypto/curve25519/internal/field"
) )
@ -124,10 +125,10 @@ func X25519(scalar, point []byte) ([]byte, error) {
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) { func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
var in [32]byte var in [32]byte
if l := len(scalar); l != 32 { if l := len(scalar); l != 32 {
return nil, fmt.Errorf("bad scalar length: %d, expected %d", l, 32) return nil, errors.New("bad scalar length: " + strconv.Itoa(l) + ", expected 32")
} }
if l := len(point); l != 32 { if l := len(point); l != 32 {
return nil, fmt.Errorf("bad point length: %d, expected %d", l, 32) return nil, errors.New("bad point length: " + strconv.Itoa(l) + ", expected 32")
} }
copy(in[:], scalar) copy(in[:], scalar)
if &point[0] == &Basepoint[0] { if &point[0] == &Basepoint[0] {
@ -138,7 +139,7 @@ func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
copy(base[:], point) copy(base[:], point)
ScalarMult(dst, &in, &base) ScalarMult(dst, &in, &base)
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 { if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
return nil, fmt.Errorf("bad input point: low order point") return nil, errors.New("bad input point: low order point")
} }
} }
return dst[:], nil return dst[:], nil

View file

@ -1,13 +1,16 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego
// +build amd64,gc,!purego // +build amd64,gc,!purego
package field package field
// feMul sets out = a * b. It works like feMulGeneric. // feMul sets out = a * b. It works like feMulGeneric.
//
//go:noescape //go:noescape
func feMul(out *Element, a *Element, b *Element) func feMul(out *Element, a *Element, b *Element)
// feSquare sets out = a * a. It works like feSquareGeneric. // feSquare sets out = a * a. It works like feSquareGeneric.
//
//go:noescape //go:noescape
func feSquare(out *Element, a *Element) func feSquare(out *Element, a *Element)

View file

@ -1,13 +1,7 @@
// Copyright 2016 The Go Authors. All rights reserved. // Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// In Go 1.13, the ed25519 package was promoted to the standard library as
// crypto/ed25519, and this package became a wrapper for the standard library one.
//
//go:build !go1.13
// +build !go1.13
// Package ed25519 implements the Ed25519 signature algorithm. See // Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/. // https://ed25519.cr.yp.to/.
// //
@ -16,21 +10,15 @@
// representation includes a public key suffix to make multiple signing // representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC // operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”. // 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
package ed25519 package ed25519
// This code is a port of the public domain, “ref10” implementation of ed25519
// from SUPERCOP.
import ( import (
"bytes" "crypto/ed25519"
"crypto"
cryptorand "crypto/rand"
"crypto/sha512"
"errors"
"io" "io"
"strconv"
"golang.org/x/crypto/ed25519/internal/edwards25519"
) )
const ( const (
@ -45,57 +33,21 @@ const (
) )
// PublicKey is the type of Ed25519 public keys. // PublicKey is the type of Ed25519 public keys.
type PublicKey []byte //
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. // PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
type PrivateKey []byte //
// This type is an alias for crypto/ed25519's PrivateKey type.
// Public returns the PublicKey corresponding to priv. // See the crypto/ed25519 package for the methods on this type.
func (priv PrivateKey) Public() crypto.PublicKey { type PrivateKey = ed25519.PrivateKey
publicKey := make([]byte, PublicKeySize)
copy(publicKey, priv[32:])
return PublicKey(publicKey)
}
// Seed returns the private key seed corresponding to priv. It is provided for
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
// in this package.
func (priv PrivateKey) Seed() []byte {
seed := make([]byte, SeedSize)
copy(seed, priv[:32])
return seed
}
// Sign signs the given message with priv.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
// indicate the message hasn't been hashed. This can be achieved by passing
// crypto.Hash(0) as the value for opts.
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
if opts.HashFunc() != crypto.Hash(0) {
return nil, errors.New("ed25519: cannot sign hashed message")
}
return Sign(priv, message), nil
}
// GenerateKey generates a public/private key pair using entropy from rand. // GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used. // If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
if rand == nil { return ed25519.GenerateKey(rand)
rand = cryptorand.Reader
}
seed := make([]byte, SeedSize)
if _, err := io.ReadFull(rand, seed); err != nil {
return nil, nil, err
}
privateKey := NewKeyFromSeed(seed)
publicKey := make([]byte, PublicKeySize)
copy(publicKey, privateKey[32:])
return publicKey, privateKey, nil
} }
// NewKeyFromSeed calculates a private key from a seed. It will panic if // NewKeyFromSeed calculates a private key from a seed. It will panic if
@ -103,121 +55,17 @@ func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
// with RFC 8032. RFC 8032's private keys correspond to seeds in this // with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package. // package.
func NewKeyFromSeed(seed []byte) PrivateKey { func NewKeyFromSeed(seed []byte) PrivateKey {
if l := len(seed); l != SeedSize { return ed25519.NewKeyFromSeed(seed)
panic("ed25519: bad seed length: " + strconv.Itoa(l))
}
digest := sha512.Sum512(seed)
digest[0] &= 248
digest[31] &= 127
digest[31] |= 64
var A edwards25519.ExtendedGroupElement
var hBytes [32]byte
copy(hBytes[:], digest[:])
edwards25519.GeScalarMultBase(&A, &hBytes)
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
privateKey := make([]byte, PrivateKeySize)
copy(privateKey, seed)
copy(privateKey[32:], publicKeyBytes[:])
return privateKey
} }
// Sign signs the message with privateKey and returns a signature. It will // Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize. // panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte { func Sign(privateKey PrivateKey, message []byte) []byte {
if l := len(privateKey); l != PrivateKeySize { return ed25519.Sign(privateKey, message)
panic("ed25519: bad private key length: " + strconv.Itoa(l))
}
h := sha512.New()
h.Write(privateKey[:32])
var digest1, messageDigest, hramDigest [64]byte
var expandedSecretKey [32]byte
h.Sum(digest1[:0])
copy(expandedSecretKey[:], digest1[:])
expandedSecretKey[0] &= 248
expandedSecretKey[31] &= 63
expandedSecretKey[31] |= 64
h.Reset()
h.Write(digest1[32:])
h.Write(message)
h.Sum(messageDigest[:0])
var messageDigestReduced [32]byte
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
var R edwards25519.ExtendedGroupElement
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
var encodedR [32]byte
R.ToBytes(&encodedR)
h.Reset()
h.Write(encodedR[:])
h.Write(privateKey[32:])
h.Write(message)
h.Sum(hramDigest[:0])
var hramDigestReduced [32]byte
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
var s [32]byte
edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
signature := make([]byte, SignatureSize)
copy(signature[:], encodedR[:])
copy(signature[32:], s[:])
return signature
} }
// Verify reports whether sig is a valid signature of message by publicKey. It // Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize. // will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool { func Verify(publicKey PublicKey, message, sig []byte) bool {
if l := len(publicKey); l != PublicKeySize { return ed25519.Verify(publicKey, message, sig)
panic("ed25519: bad public key length: " + strconv.Itoa(l))
}
if len(sig) != SignatureSize || sig[63]&224 != 0 {
return false
}
var A edwards25519.ExtendedGroupElement
var publicKeyBytes [32]byte
copy(publicKeyBytes[:], publicKey)
if !A.FromBytes(&publicKeyBytes) {
return false
}
edwards25519.FeNeg(&A.X, &A.X)
edwards25519.FeNeg(&A.T, &A.T)
h := sha512.New()
h.Write(sig[:32])
h.Write(publicKey[:])
h.Write(message)
var digest [64]byte
h.Sum(digest[:0])
var hReduced [32]byte
edwards25519.ScReduce(&hReduced, &digest)
var R edwards25519.ProjectiveGroupElement
var s [32]byte
copy(s[:], sig[32:])
// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
// the range [0, order) in order to prevent signature malleability.
if !edwards25519.ScMinimal(&s) {
return false
}
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)
var checkR [32]byte
R.ToBytes(&checkR)
return bytes.Equal(sig[:32], checkR[:])
} }

View file

@ -1,74 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.13
// +build go1.13
// Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
package ed25519
import (
"crypto/ed25519"
"io"
)
const (
// PublicKeySize is the size, in bytes, of public keys as used in this package.
PublicKeySize = 32
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
//
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
//
// This type is an alias for crypto/ed25519's PrivateKey type.
// See the crypto/ed25519 package for the methods on this type.
type PrivateKey = ed25519.PrivateKey
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
return ed25519.GenerateKey(rand)
}
// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
return ed25519.NewKeyFromSeed(seed)
}
// Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte {
return ed25519.Sign(privateKey, message)
}
// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
return ed25519.Verify(publicKey, message, sig)
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,9 +5,8 @@
//go:build !purego //go:build !purego
// +build !purego // +build !purego
// Package subtle implements functions that are often useful in cryptographic // Package alias implements memory aliasing tests.
// code but require careful thought to use correctly. package alias
package subtle // import "golang.org/x/crypto/internal/subtle"
import "unsafe" import "unsafe"

View file

@ -5,9 +5,8 @@
//go:build purego //go:build purego
// +build purego // +build purego
// Package subtle implements functions that are often useful in cryptographic // Package alias implements memory aliasing tests.
// code but require careful thought to use correctly. package alias
package subtle // import "golang.org/x/crypto/internal/subtle"
// This is the Google App Engine standard variant based on reflect // This is the Google App Engine standard variant based on reflect
// because the unsafe package and cgo are disallowed. // because the unsafe package and cgo are disallowed.

View file

@ -279,7 +279,6 @@ const (
// finalize completes the modular reduction of h and computes // finalize completes the modular reduction of h and computes
// //
// out = h + s mod 2¹²⁸ // out = h + s mod 2¹²⁸
//
func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) {
h0, h1, h2 := h[0], h[1], h[2] h0, h1, h2 := h[0], h[1], h[2]

View file

@ -14,6 +14,7 @@ import (
// updateVX is an assembly implementation of Poly1305 that uses vector // updateVX is an assembly implementation of Poly1305 that uses vector
// instructions. It must only be called if the vector facility (vx) is // instructions. It must only be called if the vector facility (vx) is
// available. // available.
//
//go:noescape //go:noescape
func updateVX(state *macState, msg []byte) func updateVX(state *macState, msg []byte)

View file

@ -35,8 +35,8 @@ This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
package secretbox // import "golang.org/x/crypto/nacl/secretbox" package secretbox // import "golang.org/x/crypto/nacl/secretbox"
import ( import (
"golang.org/x/crypto/internal/alias"
"golang.org/x/crypto/internal/poly1305" "golang.org/x/crypto/internal/poly1305"
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/salsa20/salsa" "golang.org/x/crypto/salsa20/salsa"
) )
@ -88,7 +88,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
copy(poly1305Key[:], firstBlock[:]) copy(poly1305Key[:], firstBlock[:])
ret, out := sliceForAppend(out, len(message)+poly1305.TagSize) ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
if subtle.AnyOverlap(out, message) { if alias.AnyOverlap(out, message) {
panic("nacl: invalid buffer overlap") panic("nacl: invalid buffer overlap")
} }
@ -147,7 +147,7 @@ func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
} }
ret, out := sliceForAppend(out, len(box)-Overhead) ret, out := sliceForAppend(out, len(box)-Overhead)
if subtle.AnyOverlap(out, box) { if alias.AnyOverlap(out, box) {
panic("nacl: invalid buffer overlap") panic("nacl: invalid buffer overlap")
} }

View file

@ -23,12 +23,14 @@ import (
// A Block represents an OpenPGP armored structure. // A Block represents an OpenPGP armored structure.
// //
// The encoded form is: // The encoded form is:
//
// -----BEGIN Type----- // -----BEGIN Type-----
// Headers // Headers
// //
// base64-encoded Bytes // base64-encoded Bytes
// '=' base64 encoded checksum // '=' base64 encoded checksum
// -----END Type----- // -----END Type-----
//
// where Headers is a possibly empty sequence of Key: Value lines. // where Headers is a possibly empty sequence of Key: Value lines.
// //
// Since the armored data can be very large, this package presents a streaming // Since the armored data can be very large, this package presents a streaming

View file

@ -96,6 +96,7 @@ func (l *lineBreaker) Close() (err error) {
// trailer. // trailer.
// //
// It's built into a stack of io.Writers: // It's built into a stack of io.Writers:
//
// encoding -> base64 encoder -> lineBreaker -> out // encoding -> base64 encoder -> lineBreaker -> out
type encoding struct { type encoding struct {
out io.Writer out io.Writer

View file

@ -77,8 +77,8 @@ func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err
// returns the plaintext of the message. An error can result only if the // returns the plaintext of the message. An error can result only if the
// ciphertext is invalid. Users should keep in mind that this is a padding // ciphertext is invalid. Users should keep in mind that this is a padding
// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can // oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks // be used to break the cryptosystem. See Chosen Ciphertext Attacks
// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel // Against Protocols Based on the RSA Encryption Standard PKCS #1, Daniel
// Bleichenbacher, Advances in Cryptology (Crypto '98), // Bleichenbacher, Advances in Cryptology (Crypto '98),
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) { func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
s := new(big.Int).Exp(c1, priv.X, priv.P) s := new(big.Int).Exp(c1, priv.X, priv.P)

View file

@ -7,7 +7,6 @@ package packet
import ( import (
"bytes" "bytes"
"io" "io"
"io/ioutil"
"golang.org/x/crypto/openpgp/errors" "golang.org/x/crypto/openpgp/errors"
) )
@ -26,7 +25,7 @@ type OpaquePacket struct {
} }
func (op *OpaquePacket) parse(r io.Reader) (err error) { func (op *OpaquePacket) parse(r io.Reader) (err error) {
op.Contents, err = ioutil.ReadAll(r) op.Contents, err = io.ReadAll(r)
return return
} }

View file

@ -13,7 +13,6 @@ import (
"crypto/rsa" "crypto/rsa"
"crypto/sha1" "crypto/sha1"
"io" "io"
"io/ioutil"
"math/big" "math/big"
"strconv" "strconv"
"time" "time"
@ -133,7 +132,7 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) {
} }
} }
pk.encryptedData, err = ioutil.ReadAll(r) pk.encryptedData, err = io.ReadAll(r)
if err != nil { if err != nil {
return return
} }

View file

@ -236,7 +236,7 @@ func (w *seMDCWriter) Close() (err error) {
return w.w.Close() return w.w.Close()
} }
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. // noOpCloser is like an io.NopCloser, but for an io.Writer.
type noOpCloser struct { type noOpCloser struct {
w io.Writer w io.Writer
} }

View file

@ -9,7 +9,6 @@ import (
"image" "image"
"image/jpeg" "image/jpeg"
"io" "io"
"io/ioutil"
) )
const UserAttrImageSubpacket = 1 const UserAttrImageSubpacket = 1
@ -56,7 +55,7 @@ func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute {
func (uat *UserAttribute) parse(r io.Reader) (err error) { func (uat *UserAttribute) parse(r io.Reader) (err error) {
// RFC 4880, section 5.13 // RFC 4880, section 5.13
b, err := ioutil.ReadAll(r) b, err := io.ReadAll(r)
if err != nil { if err != nil {
return return
} }

View file

@ -6,7 +6,6 @@ package packet
import ( import (
"io" "io"
"io/ioutil"
"strings" "strings"
) )
@ -66,7 +65,7 @@ func NewUserId(name, comment, email string) *UserId {
func (uid *UserId) parse(r io.Reader) (err error) { func (uid *UserId) parse(r io.Reader) (err error) {
// RFC 4880, section 5.11 // RFC 4880, section 5.11
b, err := ioutil.ReadAll(r) b, err := io.ReadAll(r)
if err != nil { if err != nil {
return return
} }

View file

@ -268,7 +268,7 @@ func HashIdToString(id byte) (name string, ok bool) {
return "", false return "", false
} }
// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash. // HashToHashId returns an OpenPGP hash id which corresponds the given Hash.
func HashToHashId(h crypto.Hash) (id byte, ok bool) { func HashToHashId(h crypto.Hash) (id byte, ok bool) {
for _, m := range hashToHashIdMapping { for _, m := range hashToHashIdMapping {
if m.hash == h { if m.hash == h {

View file

@ -402,7 +402,7 @@ func (s signatureWriter) Close() error {
return s.encryptedData.Close() return s.encryptedData.Close()
} }
// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. // noOpCloser is like an io.NopCloser, but for an io.Writer.
// TODO: we have two of these in OpenPGP packages alone. This probably needs // TODO: we have two of these in OpenPGP packages alone. This probably needs
// to be promoted somewhere more common. // to be promoted somewhere more common.
type noOpCloser struct { type noOpCloser struct {

View file

@ -8,8 +8,7 @@
// Both types of hash function use the "sponge" construction and the Keccak // Both types of hash function use the "sponge" construction and the Keccak
// permutation. For a detailed specification see http://keccak.noekeon.org/ // permutation. For a detailed specification see http://keccak.noekeon.org/
// //
// // # Guidance
// Guidance
// //
// If you aren't sure what function you need, use SHAKE256 with at least 64 // If you aren't sure what function you need, use SHAKE256 with at least 64
// bytes of output. The SHAKE instances are faster than the SHA3 instances; // bytes of output. The SHAKE instances are faster than the SHA3 instances;
@ -19,8 +18,7 @@
// secret key to the input, hash with SHAKE256 and read at least 32 bytes of // secret key to the input, hash with SHAKE256 and read at least 32 bytes of
// output. // output.
// //
// // # Security strengths
// Security strengths
// //
// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security // The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
// strength against preimage attacks of x bits. Since they only produce "x" // strength against preimage attacks of x bits. Since they only produce "x"
@ -31,8 +29,7 @@
// is used. Requesting more than 64 or 32 bytes of output, respectively, does // is used. Requesting more than 64 or 32 bytes of output, respectively, does
// not increase the collision-resistance of the SHAKE functions. // not increase the collision-resistance of the SHAKE functions.
// //
// // # The sponge construction
// The sponge construction
// //
// A sponge builds a pseudo-random function from a public pseudo-random // A sponge builds a pseudo-random function from a public pseudo-random
// permutation, by applying the permutation to a state of "rate + capacity" // permutation, by applying the permutation to a state of "rate + capacity"
@ -50,8 +47,7 @@
// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means // Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. // that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
// //
// // # Recommendations
// Recommendations
// //
// The SHAKE functions are recommended for most new uses. They can produce // The SHAKE functions are recommended for most new uses. They can produce
// output of arbitrary length. SHAKE256, with an output length of at least // output of arbitrary length. SHAKE256, with an output length of at least

View file

@ -86,7 +86,7 @@ func (d *state) permute() {
d.buf = d.storage.asBytes()[:0] d.buf = d.storage.asBytes()[:0]
keccakF1600(&d.a) keccakF1600(&d.a)
case spongeSqueezing: case spongeSqueezing:
// If we're squeezing, we need to apply the permutatin before // If we're squeezing, we need to apply the permutation before
// copying more output. // copying more output.
keccakF1600(&d.a) keccakF1600(&d.a)
d.buf = d.storage.asBytes()[:d.rate] d.buf = d.storage.asBytes()[:d.rate]

View file

@ -34,11 +34,13 @@ const (
// kimd is a wrapper for the 'compute intermediate message digest' instruction. // kimd is a wrapper for the 'compute intermediate message digest' instruction.
// src must be a multiple of the rate for the given function code. // src must be a multiple of the rate for the given function code.
//
//go:noescape //go:noescape
func kimd(function code, chain *[200]byte, src []byte) func kimd(function code, chain *[200]byte, src []byte)
// klmd is a wrapper for the 'compute last message digest' instruction. // klmd is a wrapper for the 'compute last message digest' instruction.
// src padding is handled by the instruction. // src padding is handled by the instruction.
//
//go:noescape //go:noescape
func klmd(function code, chain *[200]byte, dst, src []byte) func klmd(function code, chain *[200]byte, dst, src []byte)

View file

@ -8,6 +8,7 @@
// ssh-agent process using the sample server. // ssh-agent process using the sample server.
// //
// References: // References:
//
// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00 // [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00
package agent // import "golang.org/x/crypto/ssh/agent" package agent // import "golang.org/x/crypto/ssh/agent"
@ -25,7 +26,6 @@ import (
"math/big" "math/big"
"sync" "sync"
"crypto"
"golang.org/x/crypto/ed25519" "golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
@ -93,7 +93,7 @@ type ExtendedAgent interface {
type ConstraintExtension struct { type ConstraintExtension struct {
// ExtensionName consist of a UTF-8 string suffixed by the // ExtensionName consist of a UTF-8 string suffixed by the
// implementation domain following the naming scheme defined // implementation domain following the naming scheme defined
// in Section 4.2 of [RFC4251], e.g. "foo@example.com". // in Section 4.2 of RFC 4251, e.g. "foo@example.com".
ExtensionName string ExtensionName string
// ExtensionDetails contains the actual content of the extended // ExtensionDetails contains the actual content of the extended
// constraint. // constraint.
@ -226,7 +226,9 @@ var ErrExtensionUnsupported = errors.New("agent: extension unsupported")
type extensionAgentMsg struct { type extensionAgentMsg struct {
ExtensionType string `sshtype:"27"` ExtensionType string `sshtype:"27"`
Contents []byte // NOTE: this matches OpenSSH's PROTOCOL.agent, not the IETF draft [PROTOCOL.agent],
// so that it matches what OpenSSH actually implements in the wild.
Contents []byte `ssh:"rest"`
} }
// Key represents a protocol 2 public key as defined in // Key represents a protocol 2 public key as defined in
@ -729,7 +731,7 @@ func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string
if err != nil { if err != nil {
return err return err
} }
if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { if !bytes.Equal(cert.Key.Marshal(), signer.PublicKey().Marshal()) {
return errors.New("agent: signer and cert have different public key") return errors.New("agent: signer and cert have different public key")
} }
@ -771,19 +773,53 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature,
return s.agent.Sign(s.pub, data) return s.agent.Sign(s.pub, data)
} }
func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) { func (s *agentKeyringSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*ssh.Signature, error) {
if algorithm == "" || algorithm == underlyingAlgo(s.pub.Type()) {
return s.Sign(rand, data)
}
var flags SignatureFlags var flags SignatureFlags
if opts != nil { switch algorithm {
switch opts.HashFunc() { case ssh.KeyAlgoRSASHA256:
case crypto.SHA256:
flags = SignatureFlagRsaSha256 flags = SignatureFlagRsaSha256
case crypto.SHA512: case ssh.KeyAlgoRSASHA512:
flags = SignatureFlagRsaSha512 flags = SignatureFlagRsaSha512
default:
return nil, fmt.Errorf("agent: unsupported algorithm %q", algorithm)
} }
}
return s.agent.SignWithFlags(s.pub, data, flags) return s.agent.SignWithFlags(s.pub, data, flags)
} }
var _ ssh.AlgorithmSigner = &agentKeyringSigner{}
// certKeyAlgoNames is a mapping from known certificate algorithm names to the
// corresponding public key signature algorithm.
//
// This map must be kept in sync with the one in certs.go.
var certKeyAlgoNames = map[string]string{
ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA,
ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256,
ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512,
ssh.CertAlgoDSAv01: ssh.KeyAlgoDSA,
ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256,
ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384,
ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521,
ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256,
ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519,
ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519,
}
// underlyingAlgo returns the signature algorithm associated with algo (which is
// an advertised or negotiated public key or host key algorithm). These are
// usually the same, except for certificate algorithms.
func underlyingAlgo(algo string) string {
if a, ok := certKeyAlgoNames[algo]; ok {
return a
}
return algo
}
// Calls an extension method. It is up to the agent implementation as to whether or not // Calls an extension method. It is up to the agent implementation as to whether or not
// any particular extension is supported and may always return an error. Because the // any particular extension is supported and may always return an error. Because the
// type of the response is up to the implementation, this returns the bytes of the // type of the response is up to the implementation, this returns the bytes of the

View file

@ -113,7 +113,7 @@ func (r *keyring) Unlock(passphrase []byte) error {
// expireKeysLocked removes expired keys from the keyring. If a key was added // expireKeysLocked removes expired keys from the keyring. If a key was added
// with a lifetimesecs contraint and seconds >= lifetimesecs seconds have // with a lifetimesecs contraint and seconds >= lifetimesecs seconds have
// ellapsed, it is removed. The caller *must* be holding the keyring mutex. // elapsed, it is removed. The caller *must* be holding the keyring mutex.
func (r *keyring) expireKeysLocked() { func (r *keyring) expireKeysLocked() {
for _, k := range r.keys { for _, k := range r.keys {
if k.expire != nil && time.Now().After(*k.expire) { if k.expire != nil && time.Now().After(*k.expire) {
@ -205,9 +205,9 @@ func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureF
var algorithm string var algorithm string
switch flags { switch flags {
case SignatureFlagRsaSha256: case SignatureFlagRsaSha256:
algorithm = ssh.SigAlgoRSASHA2256 algorithm = ssh.KeyAlgoRSASHA256
case SignatureFlagRsaSha512: case SignatureFlagRsaSha512:
algorithm = ssh.SigAlgoRSASHA2512 algorithm = ssh.KeyAlgoRSASHA512
default: default:
return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags)
} }

View file

@ -14,8 +14,10 @@ import (
"time" "time"
) )
// These constants from [PROTOCOL.certkeys] represent the key algorithm names // Certificate algorithm names from [PROTOCOL.certkeys]. These values can appear
// for certificate types supported by this package. // in Certificate.Type, PublicKey.Type, and ClientConfig.HostKeyAlgorithms.
// Unlike key algorithm names, these are not passed to AlgorithmSigner and don't
// appear in the Signature.Format field.
const ( const (
CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com" CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
@ -25,14 +27,21 @@ const (
CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com" CertAlgoSKECDSA256v01 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com" CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com" CertAlgoSKED25519v01 = "sk-ssh-ed25519-cert-v01@openssh.com"
// CertAlgoRSASHA256v01 and CertAlgoRSASHA512v01 can't appear as a
// Certificate.Type (or PublicKey.Type), but only in
// ClientConfig.HostKeyAlgorithms.
CertAlgoRSASHA256v01 = "rsa-sha2-256-cert-v01@openssh.com"
CertAlgoRSASHA512v01 = "rsa-sha2-512-cert-v01@openssh.com"
) )
// These constants from [PROTOCOL.certkeys] represent additional signature
// algorithm names for certificate types supported by this package.
const ( const (
CertSigAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" // Deprecated: use CertAlgoRSAv01.
CertSigAlgoRSASHA2256v01 = "rsa-sha2-256-cert-v01@openssh.com" CertSigAlgoRSAv01 = CertAlgoRSAv01
CertSigAlgoRSASHA2512v01 = "rsa-sha2-512-cert-v01@openssh.com" // Deprecated: use CertAlgoRSASHA256v01.
CertSigAlgoRSASHA2256v01 = CertAlgoRSASHA256v01
// Deprecated: use CertAlgoRSASHA512v01.
CertSigAlgoRSASHA2512v01 = CertAlgoRSASHA512v01
) )
// Certificate types distinguish between host and user // Certificate types distinguish between host and user
@ -242,7 +251,7 @@ type algorithmOpenSSHCertSigner struct {
// private key is held by signer. It returns an error if the public key in cert // private key is held by signer. It returns an error if the public key in cert
// doesn't match the key used by signer. // doesn't match the key used by signer.
func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { if !bytes.Equal(cert.Key.Marshal(), signer.PublicKey().Marshal()) {
return nil, errors.New("ssh: signer and cert have different public key") return nil, errors.New("ssh: signer and cert have different public key")
} }
@ -431,10 +440,14 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
} }
c.SignatureKey = authority.PublicKey() c.SignatureKey = authority.PublicKey()
if v, ok := authority.(AlgorithmSigner); ok { // Default to KeyAlgoRSASHA512 for ssh-rsa signers.
if v.PublicKey().Type() == KeyAlgoRSA { if v, ok := authority.(AlgorithmSigner); ok && v.PublicKey().Type() == KeyAlgoRSA {
authority = &rsaSigner{v, SigAlgoRSASHA2512} sig, err := v.SignWithAlgorithm(rand, c.bytesForSigning(), KeyAlgoRSASHA512)
if err != nil {
return err
} }
c.Signature = sig
return nil
} }
sig, err := authority.Sign(rand, c.bytesForSigning()) sig, err := authority.Sign(rand, c.bytesForSigning())
@ -445,32 +458,42 @@ func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
return nil return nil
} }
// certAlgoNames includes a mapping from signature algorithms to the // certKeyAlgoNames is a mapping from known certificate algorithm names to the
// corresponding certificate signature algorithm. When a key type (such // corresponding public key signature algorithm.
// as ED25516) is associated with only one algorithm, the KeyAlgo //
// constant is used instead of the SigAlgo. // This map must be kept in sync with the one in agent/client.go.
var certAlgoNames = map[string]string{ var certKeyAlgoNames = map[string]string{
SigAlgoRSA: CertSigAlgoRSAv01, CertAlgoRSAv01: KeyAlgoRSA,
SigAlgoRSASHA2256: CertSigAlgoRSASHA2256v01, CertAlgoRSASHA256v01: KeyAlgoRSASHA256,
SigAlgoRSASHA2512: CertSigAlgoRSASHA2512v01, CertAlgoRSASHA512v01: KeyAlgoRSASHA512,
KeyAlgoDSA: CertAlgoDSAv01, CertAlgoDSAv01: KeyAlgoDSA,
KeyAlgoECDSA256: CertAlgoECDSA256v01, CertAlgoECDSA256v01: KeyAlgoECDSA256,
KeyAlgoECDSA384: CertAlgoECDSA384v01, CertAlgoECDSA384v01: KeyAlgoECDSA384,
KeyAlgoECDSA521: CertAlgoECDSA521v01, CertAlgoECDSA521v01: KeyAlgoECDSA521,
KeyAlgoSKECDSA256: CertAlgoSKECDSA256v01, CertAlgoSKECDSA256v01: KeyAlgoSKECDSA256,
KeyAlgoED25519: CertAlgoED25519v01, CertAlgoED25519v01: KeyAlgoED25519,
KeyAlgoSKED25519: CertAlgoSKED25519v01, CertAlgoSKED25519v01: KeyAlgoSKED25519,
} }
// certToPrivAlgo returns the underlying algorithm for a certificate algorithm. // underlyingAlgo returns the signature algorithm associated with algo (which is
// Panics if a non-certificate algorithm is passed. // an advertised or negotiated public key or host key algorithm). These are
func certToPrivAlgo(algo string) string { // usually the same, except for certificate algorithms.
for privAlgo, pubAlgo := range certAlgoNames { func underlyingAlgo(algo string) string {
if pubAlgo == algo { if a, ok := certKeyAlgoNames[algo]; ok {
return privAlgo return a
}
return algo
}
// certificateAlgo returns the certificate algorithms that uses the provided
// underlying signature algorithm.
func certificateAlgo(algo string) (certAlgo string, ok bool) {
for certName, algoName := range certKeyAlgoNames {
if algoName == algo {
return certName, true
} }
} }
panic("unknown cert algorithm") return "", false
} }
func (cert *Certificate) bytesForSigning() []byte { func (cert *Certificate) bytesForSigning() []byte {
@ -514,13 +537,13 @@ func (c *Certificate) Marshal() []byte {
return result return result
} }
// Type returns the key name. It is part of the PublicKey interface. // Type returns the certificate algorithm name. It is part of the PublicKey interface.
func (c *Certificate) Type() string { func (c *Certificate) Type() string {
algo, ok := certAlgoNames[c.Key.Type()] certName, ok := certificateAlgo(c.Key.Type())
if !ok { if !ok {
panic("unknown cert key type " + c.Key.Type()) panic("unknown certificate type for key type " + c.Key.Type())
} }
return algo return certName
} }
// Verify verifies a signature against the certificate's public // Verify verifies a signature against the certificate's public

View file

@ -15,7 +15,6 @@ import (
"fmt" "fmt"
"hash" "hash"
"io" "io"
"io/ioutil"
"golang.org/x/crypto/chacha20" "golang.org/x/crypto/chacha20"
"golang.org/x/crypto/internal/poly1305" "golang.org/x/crypto/internal/poly1305"
@ -497,7 +496,7 @@ func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error)
// data, to make distinguishing between // data, to make distinguishing between
// failing MAC and failing length check more // failing MAC and failing length check more
// difficult. // difficult.
io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) io.CopyN(io.Discard, r, int64(c.oracleCamouflage))
} }
} }
return p, err return p, err

View file

@ -113,25 +113,16 @@ func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) e
return c.clientAuthenticate(config) return c.clientAuthenticate(config)
} }
// verifyHostKeySignature verifies the host key obtained in the key // verifyHostKeySignature verifies the host key obtained in the key exchange.
// exchange. // algo is the negotiated algorithm, and may be a certificate type.
func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error { func verifyHostKeySignature(hostKey PublicKey, algo string, result *kexResult) error {
sig, rest, ok := parseSignatureBody(result.Signature) sig, rest, ok := parseSignatureBody(result.Signature)
if len(rest) > 0 || !ok { if len(rest) > 0 || !ok {
return errors.New("ssh: signature parse error") return errors.New("ssh: signature parse error")
} }
// For keys, underlyingAlgo is exactly algo. For certificates, if a := underlyingAlgo(algo); sig.Format != a {
// we have to look up the underlying key algorithm that SSH return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, a)
// uses to evaluate signatures.
underlyingAlgo := algo
for sigAlgo, certAlgo := range certAlgoNames {
if certAlgo == algo {
underlyingAlgo = sigAlgo
}
}
if sig.Format != underlyingAlgo {
return fmt.Errorf("ssh: invalid signature algorithm %q, expected %q", sig.Format, underlyingAlgo)
} }
return hostKey.Verify(result.H, sig) return hostKey.Verify(result.H, sig)
@ -237,11 +228,11 @@ type ClientConfig struct {
// be used for the connection. If empty, a reasonable default is used. // be used for the connection. If empty, a reasonable default is used.
ClientVersion string ClientVersion string
// HostKeyAlgorithms lists the key types that the client will // HostKeyAlgorithms lists the public key algorithms that the client will
// accept from the server as host key, in order of // accept from the server for host key authentication, in order of
// preference. If empty, a reasonable default is used. Any // preference. If empty, a reasonable default is used. Any
// string returned from PublicKey.Type method may be used, or // string returned from a PublicKey.Type method may be used, or
// any of the CertAlgoXxxx and KeyAlgoXxxx constants. // any of the CertAlgo and KeyAlgo constants.
HostKeyAlgorithms []string HostKeyAlgorithms []string
// Timeout is the maximum amount of time for the TCP connection to establish. // Timeout is the maximum amount of time for the TCP connection to establish.

View file

@ -9,6 +9,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"strings"
) )
type authResult int type authResult int
@ -29,6 +30,33 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
if err != nil { if err != nil {
return err return err
} }
// The server may choose to send a SSH_MSG_EXT_INFO at this point (if we
// advertised willingness to receive one, which we always do) or not. See
// RFC 8308, Section 2.4.
extensions := make(map[string][]byte)
if len(packet) > 0 && packet[0] == msgExtInfo {
var extInfo extInfoMsg
if err := Unmarshal(packet, &extInfo); err != nil {
return err
}
payload := extInfo.Payload
for i := uint32(0); i < extInfo.NumExtensions; i++ {
name, rest, ok := parseString(payload)
if !ok {
return parseError(msgExtInfo)
}
value, rest, ok := parseString(rest)
if !ok {
return parseError(msgExtInfo)
}
extensions[string(name)] = value
payload = rest
}
packet, err = c.transport.readPacket()
if err != nil {
return err
}
}
var serviceAccept serviceAcceptMsg var serviceAccept serviceAcceptMsg
if err := Unmarshal(packet, &serviceAccept); err != nil { if err := Unmarshal(packet, &serviceAccept); err != nil {
return err return err
@ -41,7 +69,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
sessionID := c.transport.getSessionID() sessionID := c.transport.getSessionID()
for auth := AuthMethod(new(noneAuth)); auth != nil; { for auth := AuthMethod(new(noneAuth)); auth != nil; {
ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand) ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand, extensions)
if err != nil { if err != nil {
return err return err
} }
@ -93,7 +121,7 @@ type AuthMethod interface {
// If authentication is not successful, a []string of alternative // If authentication is not successful, a []string of alternative
// method names is returned. If the slice is nil, it will be ignored // method names is returned. If the slice is nil, it will be ignored
// and the previous set of possible methods will be reused. // and the previous set of possible methods will be reused.
auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error) auth(session []byte, user string, p packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error)
// method returns the RFC 4252 method name. // method returns the RFC 4252 method name.
method() string method() string
@ -102,7 +130,7 @@ type AuthMethod interface {
// "none" authentication, RFC 4252 section 5.2. // "none" authentication, RFC 4252 section 5.2.
type noneAuth int type noneAuth int
func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
if err := c.writePacket(Marshal(&userAuthRequestMsg{ if err := c.writePacket(Marshal(&userAuthRequestMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
@ -122,7 +150,7 @@ func (n *noneAuth) method() string {
// a function call, e.g. by prompting the user. // a function call, e.g. by prompting the user.
type passwordCallback func() (password string, err error) type passwordCallback func() (password string, err error)
func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
type passwordAuthMsg struct { type passwordAuthMsg struct {
User string `sshtype:"50"` User string `sshtype:"50"`
Service string Service string
@ -189,7 +217,46 @@ func (cb publicKeyCallback) method() string {
return "publickey" return "publickey"
} }
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (as AlgorithmSigner, algo string) {
keyFormat := signer.PublicKey().Type()
// Like in sendKexInit, if the public key implements AlgorithmSigner we
// assume it supports all algorithms, otherwise only the key format one.
as, ok := signer.(AlgorithmSigner)
if !ok {
return algorithmSignerWrapper{signer}, keyFormat
}
extPayload, ok := extensions["server-sig-algs"]
if !ok {
// If there is no "server-sig-algs" extension, fall back to the key
// format algorithm.
return as, keyFormat
}
// The server-sig-algs extension only carries underlying signature
// algorithm, but we are trying to select a protocol-level public key
// algorithm, which might be a certificate type. Extend the list of server
// supported algorithms to include the corresponding certificate algorithms.
serverAlgos := strings.Split(string(extPayload), ",")
for _, algo := range serverAlgos {
if certAlgo, ok := certificateAlgo(algo); ok {
serverAlgos = append(serverAlgos, certAlgo)
}
}
keyAlgos := algorithmsForKeyFormat(keyFormat)
algo, err := findCommon("public key signature algorithm", keyAlgos, serverAlgos)
if err != nil {
// If there is no overlap, try the key anyway with the key format
// algorithm, to support servers that fail to list all supported
// algorithms.
return as, keyFormat
}
return as, algo
}
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
// Authentication is performed by sending an enquiry to test if a key is // Authentication is performed by sending an enquiry to test if a key is
// acceptable to the remote. If the key is acceptable, the client will // acceptable to the remote. If the key is acceptable, the client will
// attempt to authenticate with the valid key. If not the client will repeat // attempt to authenticate with the valid key. If not the client will repeat
@ -201,7 +268,10 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
} }
var methods []string var methods []string
for _, signer := range signers { for _, signer := range signers {
ok, err := validateKey(signer.PublicKey(), user, c) pub := signer.PublicKey()
as, algo := pickSignatureAlgorithm(signer, extensions)
ok, err := validateKey(pub, algo, user, c)
if err != nil { if err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
@ -209,13 +279,13 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
continue continue
} }
pub := signer.PublicKey()
pubKey := pub.Marshal() pubKey := pub.Marshal()
sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{ data := buildDataSignedForAuth(session, userAuthRequestMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
Method: cb.method(), Method: cb.method(),
}, []byte(pub.Type()), pubKey)) }, algo, pubKey)
sign, err := as.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
if err != nil { if err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
@ -229,7 +299,7 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
Service: serviceSSH, Service: serviceSSH,
Method: cb.method(), Method: cb.method(),
HasSig: true, HasSig: true,
Algoname: pub.Type(), Algoname: algo,
PubKey: pubKey, PubKey: pubKey,
Sig: sig, Sig: sig,
} }
@ -266,26 +336,25 @@ func containsMethod(methods []string, method string) bool {
} }
// validateKey validates the key provided is acceptable to the server. // validateKey validates the key provided is acceptable to the server.
func validateKey(key PublicKey, user string, c packetConn) (bool, error) { func validateKey(key PublicKey, algo string, user string, c packetConn) (bool, error) {
pubKey := key.Marshal() pubKey := key.Marshal()
msg := publickeyAuthMsg{ msg := publickeyAuthMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
Method: "publickey", Method: "publickey",
HasSig: false, HasSig: false,
Algoname: key.Type(), Algoname: algo,
PubKey: pubKey, PubKey: pubKey,
} }
if err := c.writePacket(Marshal(&msg)); err != nil { if err := c.writePacket(Marshal(&msg)); err != nil {
return false, err return false, err
} }
return confirmKeyAck(key, c) return confirmKeyAck(key, algo, c)
} }
func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { func confirmKeyAck(key PublicKey, algo string, c packetConn) (bool, error) {
pubKey := key.Marshal() pubKey := key.Marshal()
algoname := key.Type()
for { for {
packet, err := c.readPacket() packet, err := c.readPacket()
@ -302,14 +371,14 @@ func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
if err := Unmarshal(packet, &msg); err != nil { if err := Unmarshal(packet, &msg); err != nil {
return false, err return false, err
} }
if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) { if msg.Algo != algo || !bytes.Equal(msg.PubKey, pubKey) {
return false, nil return false, nil
} }
return true, nil return true, nil
case msgUserAuthFailure: case msgUserAuthFailure:
return false, nil return false, nil
default: default:
return false, unexpectedMessageError(msgUserAuthSuccess, packet[0]) return false, unexpectedMessageError(msgUserAuthPubKeyOk, packet[0])
} }
} }
} }
@ -330,6 +399,7 @@ func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMet
// along with a list of remaining authentication methods to try next and // along with a list of remaining authentication methods to try next and
// an error if an unexpected response was received. // an error if an unexpected response was received.
func handleAuthResponse(c packetConn) (authResult, []string, error) { func handleAuthResponse(c packetConn) (authResult, []string, error) {
gotMsgExtInfo := false
for { for {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
@ -341,6 +411,12 @@ func handleAuthResponse(c packetConn) (authResult, []string, error) {
if err := handleBannerResponse(c, packet); err != nil { if err := handleBannerResponse(c, packet); err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
case msgExtInfo:
// Ignore post-authentication RFC 8308 extensions, once.
if gotMsgExtInfo {
return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
}
gotMsgExtInfo = true
case msgUserAuthFailure: case msgUserAuthFailure:
var msg userAuthFailureMsg var msg userAuthFailureMsg
if err := Unmarshal(packet, &msg); err != nil { if err := Unmarshal(packet, &msg); err != nil {
@ -380,10 +456,10 @@ func handleBannerResponse(c packetConn, packet []byte) error {
// disabling echoing (e.g. for passwords), and return all the answers. // disabling echoing (e.g. for passwords), and return all the answers.
// Challenge may be called multiple times in a single session. After // Challenge may be called multiple times in a single session. After
// successful authentication, the server may send a challenge with no // successful authentication, the server may send a challenge with no
// questions, for which the user and instruction messages should be // questions, for which the name and instruction messages should be
// printed. RFC 4256 section 3.3 details how the UI should behave for // printed. RFC 4256 section 3.3 details how the UI should behave for
// both CLI and GUI environments. // both CLI and GUI environments.
type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) type KeyboardInteractiveChallenge func(name, instruction string, questions []string, echos []bool) (answers []string, err error)
// KeyboardInteractive returns an AuthMethod using a prompt/response // KeyboardInteractive returns an AuthMethod using a prompt/response
// sequence controlled by the server. // sequence controlled by the server.
@ -395,7 +471,7 @@ func (cb KeyboardInteractiveChallenge) method() string {
return "keyboard-interactive" return "keyboard-interactive"
} }
func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
type initiateMsg struct { type initiateMsg struct {
User string `sshtype:"50"` User string `sshtype:"50"`
Service string Service string
@ -412,6 +488,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
return authFailure, nil, err return authFailure, nil, err
} }
gotMsgExtInfo := false
for { for {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
@ -425,6 +502,13 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
return authFailure, nil, err return authFailure, nil, err
} }
continue continue
case msgExtInfo:
// Ignore post-authentication RFC 8308 extensions, once.
if gotMsgExtInfo {
return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
}
gotMsgExtInfo = true
continue
case msgUserAuthInfoRequest: case msgUserAuthInfoRequest:
// OK // OK
case msgUserAuthFailure: case msgUserAuthFailure:
@ -465,7 +549,7 @@ func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packe
return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs") return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
} }
answers, err := cb(msg.User, msg.Instruction, prompts, echos) answers, err := cb(msg.Name, msg.Instruction, prompts, echos)
if err != nil { if err != nil {
return authFailure, nil, err return authFailure, nil, err
} }
@ -497,9 +581,9 @@ type retryableAuthMethod struct {
maxTries int maxTries int
} }
func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok authResult, methods []string, err error) { func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (ok authResult, methods []string, err error) {
for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ {
ok, methods, err = r.authMethod.auth(session, user, c, rand) ok, methods, err = r.authMethod.auth(session, user, c, rand, extensions)
if ok != authFailure || err != nil { // either success, partial success or error terminate if ok != authFailure || err != nil { // either success, partial success or error terminate
return ok, methods, err return ok, methods, err
} }
@ -542,7 +626,7 @@ type gssAPIWithMICCallback struct {
target string target string
} }
func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (authResult, []string, error) { func (g *gssAPIWithMICCallback) auth(session []byte, user string, c packetConn, rand io.Reader, _ map[string][]byte) (authResult, []string, error) {
m := &userAuthRequestMsg{ m := &userAuthRequestMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,

View file

@ -44,11 +44,11 @@ var preferredCiphers = []string{
// supportedKexAlgos specifies the supported key-exchange algorithms in // supportedKexAlgos specifies the supported key-exchange algorithms in
// preference order. // preference order.
var supportedKexAlgos = []string{ var supportedKexAlgos = []string{
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
// P384 and P521 are not constant-time yet, but since we don't // P384 and P521 are not constant-time yet, but since we don't
// reuse ephemeral keys, using them for ECDH should be OK. // reuse ephemeral keys, using them for ECDH should be OK.
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
kexAlgoDH14SHA1, kexAlgoDH1SHA1, kexAlgoDH14SHA256, kexAlgoDH14SHA1, kexAlgoDH1SHA1,
} }
// serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden // serverForbiddenKexAlgos contains key exchange algorithms, that are forbidden
@ -61,21 +61,21 @@ var serverForbiddenKexAlgos = map[string]struct{}{
// preferredKexAlgos specifies the default preference for key-exchange algorithms // preferredKexAlgos specifies the default preference for key-exchange algorithms
// in preference order. // in preference order.
var preferredKexAlgos = []string{ var preferredKexAlgos = []string{
kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256, kexAlgoCurve25519SHA256LibSSH,
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
kexAlgoDH14SHA1, kexAlgoDH14SHA256, kexAlgoDH14SHA1,
} }
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
// of authenticating servers) in preference order. // of authenticating servers) in preference order.
var supportedHostKeyAlgos = []string{ var supportedHostKeyAlgos = []string{
CertSigAlgoRSASHA2512v01, CertSigAlgoRSASHA2256v01, CertAlgoRSASHA512v01, CertAlgoRSASHA256v01,
CertSigAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01,
KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
SigAlgoRSASHA2512, SigAlgoRSASHA2256, KeyAlgoRSASHA512, KeyAlgoRSASHA256,
SigAlgoRSA, KeyAlgoDSA, KeyAlgoRSA, KeyAlgoDSA,
KeyAlgoED25519, KeyAlgoED25519,
} }
@ -89,23 +89,33 @@ var supportedMACs = []string{
var supportedCompressions = []string{compressionNone} var supportedCompressions = []string{compressionNone}
// hashFuncs keeps the mapping of supported algorithms to their respective // hashFuncs keeps the mapping of supported signature algorithms to their
// hashes needed for signature verification. // respective hashes needed for signing and verification.
var hashFuncs = map[string]crypto.Hash{ var hashFuncs = map[string]crypto.Hash{
SigAlgoRSA: crypto.SHA1, KeyAlgoRSA: crypto.SHA1,
SigAlgoRSASHA2256: crypto.SHA256, KeyAlgoRSASHA256: crypto.SHA256,
SigAlgoRSASHA2512: crypto.SHA512, KeyAlgoRSASHA512: crypto.SHA512,
KeyAlgoDSA: crypto.SHA1, KeyAlgoDSA: crypto.SHA1,
KeyAlgoECDSA256: crypto.SHA256, KeyAlgoECDSA256: crypto.SHA256,
KeyAlgoECDSA384: crypto.SHA384, KeyAlgoECDSA384: crypto.SHA384,
KeyAlgoECDSA521: crypto.SHA512, KeyAlgoECDSA521: crypto.SHA512,
CertSigAlgoRSAv01: crypto.SHA1, // KeyAlgoED25519 doesn't pre-hash.
CertSigAlgoRSASHA2256v01: crypto.SHA256, KeyAlgoSKECDSA256: crypto.SHA256,
CertSigAlgoRSASHA2512v01: crypto.SHA512, KeyAlgoSKED25519: crypto.SHA256,
CertAlgoDSAv01: crypto.SHA1, }
CertAlgoECDSA256v01: crypto.SHA256,
CertAlgoECDSA384v01: crypto.SHA384, // algorithmsForKeyFormat returns the supported signature algorithms for a given
CertAlgoECDSA521v01: crypto.SHA512, // public key format (PublicKey.Type), in order of preference. See RFC 8332,
// Section 2. See also the note in sendKexInit on backwards compatibility.
func algorithmsForKeyFormat(keyFormat string) []string {
switch keyFormat {
case KeyAlgoRSA:
return []string{KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA}
case CertAlgoRSAv01:
return []string{CertAlgoRSASHA256v01, CertAlgoRSASHA512v01, CertAlgoRSAv01}
default:
return []string{keyFormat}
}
} }
// unexpectedMessageError results when the SSH message that we received didn't // unexpectedMessageError results when the SSH message that we received didn't
@ -152,6 +162,11 @@ func (a *directionAlgorithms) rekeyBytes() int64 {
return 1 << 30 return 1 << 30
} }
var aeadCiphers = map[string]bool{
gcmCipherID: true,
chacha20Poly1305ID: true,
}
type algorithms struct { type algorithms struct {
kex string kex string
hostKey string hostKey string
@ -187,15 +202,19 @@ func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMs
return return
} }
if !aeadCiphers[ctos.Cipher] {
ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) ctos.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
if err != nil { if err != nil {
return return
} }
}
if !aeadCiphers[stoc.Cipher] {
stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) stoc.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
if err != nil { if err != nil {
return return
} }
}
ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) ctos.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
if err != nil { if err != nil {
@ -278,8 +297,9 @@ func (c *Config) SetDefaults() {
} }
// buildDataSignedForAuth returns the data that is signed in order to prove // buildDataSignedForAuth returns the data that is signed in order to prove
// possession of a private key. See RFC 4252, section 7. // possession of a private key. See RFC 4252, section 7. algo is the advertised
func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { // algorithm, and may be a certificate type.
func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo string, pubKey []byte) []byte {
data := struct { data := struct {
Session []byte Session []byte
Type byte Type byte
@ -287,7 +307,7 @@ func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubK
Service string Service string
Method string Method string
Sign bool Sign bool
Algo []byte Algo string
PubKey []byte PubKey []byte
}{ }{
sessionID, sessionID,

View file

@ -12,6 +12,7 @@ the multiplexed nature of SSH is exposed to users that wish to support
others. others.
References: References:
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1

View file

@ -455,21 +455,38 @@ func (t *handshakeTransport) sendKexInit() error {
} }
io.ReadFull(rand.Reader, msg.Cookie[:]) io.ReadFull(rand.Reader, msg.Cookie[:])
if len(t.hostKeys) > 0 { isServer := len(t.hostKeys) > 0
if isServer {
for _, k := range t.hostKeys { for _, k := range t.hostKeys {
algo := k.PublicKey().Type() // If k is an AlgorithmSigner, presume it supports all signature algorithms
switch algo { // associated with the key format. (Ideally AlgorithmSigner would have a
case KeyAlgoRSA: // method to advertise supported algorithms, but it doesn't. This means that
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{SigAlgoRSASHA2512, SigAlgoRSASHA2256, SigAlgoRSA}...) // adding support for a new algorithm is a breaking change, as we will
case CertAlgoRSAv01: // immediately negotiate it even if existing implementations don't support
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, []string{CertSigAlgoRSASHA2512v01, CertSigAlgoRSASHA2256v01, CertSigAlgoRSAv01}...) // it. If that ever happens, we'll have to figure something out.)
default: // If k is not an AlgorithmSigner, we can only assume it only supports the
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo) // algorithms that matches the key format. (This means that Sign can't pick
// a different default.)
keyFormat := k.PublicKey().Type()
if _, ok := k.(AlgorithmSigner); ok {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...)
} else {
msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat)
} }
} }
} else { } else {
msg.ServerHostKeyAlgos = t.hostKeyAlgorithms msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
// As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what
// algorithms the server supports for public key authentication. See RFC
// 8308, Section 2.1.
if firstKeyExchange := t.sessionID == nil; firstKeyExchange {
msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1)
msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...)
msg.KexAlgos = append(msg.KexAlgos, "ext-info-c")
} }
}
packet := Marshal(msg) packet := Marshal(msg)
// writePacket destroys the contents, so save a copy. // writePacket destroys the contents, so save a copy.
@ -589,9 +606,9 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
var result *kexResult var result *kexResult
if len(t.hostKeys) > 0 { if len(t.hostKeys) > 0 {
result, err = t.server(kex, t.algorithms, &magics) result, err = t.server(kex, &magics)
} else { } else {
result, err = t.client(kex, t.algorithms, &magics) result, err = t.client(kex, &magics)
} }
if err != nil { if err != nil {
@ -618,33 +635,52 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
return nil return nil
} }
func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { // algorithmSignerWrapper is an AlgorithmSigner that only supports the default
var hostKey Signer // key format algorithm.
for _, k := range t.hostKeys { //
kt := k.PublicKey().Type() // This is technically a violation of the AlgorithmSigner interface, but it
if kt == algs.hostKey { // should be unreachable given where we use this. Anyway, at least it returns an
hostKey = k // error instead of panicing or producing an incorrect signature.
} else if signer, ok := k.(AlgorithmSigner); ok { type algorithmSignerWrapper struct {
// Some signature algorithms don't show up as key types Signer
// so we have to manually check for a compatible host key.
switch kt {
case KeyAlgoRSA:
if algs.hostKey == SigAlgoRSASHA2256 || algs.hostKey == SigAlgoRSASHA2512 {
hostKey = &rsaSigner{signer, algs.hostKey}
}
case CertAlgoRSAv01:
if algs.hostKey == CertSigAlgoRSASHA2256v01 || algs.hostKey == CertSigAlgoRSASHA2512v01 {
hostKey = &rsaSigner{signer, certToPrivAlgo(algs.hostKey)}
}
}
}
} }
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) func (a algorithmSignerWrapper) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
if algorithm != underlyingAlgo(a.PublicKey().Type()) {
return nil, errors.New("ssh: internal error: algorithmSignerWrapper invoked with non-default algorithm")
}
return a.Sign(rand, data)
}
func pickHostKey(hostKeys []Signer, algo string) AlgorithmSigner {
for _, k := range hostKeys {
if algo == k.PublicKey().Type() {
return algorithmSignerWrapper{k}
}
k, ok := k.(AlgorithmSigner)
if !ok {
continue
}
for _, a := range algorithmsForKeyFormat(k.PublicKey().Type()) {
if algo == a {
return k
}
}
}
return nil
}
func (t *handshakeTransport) server(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
hostKey := pickHostKey(t.hostKeys, t.algorithms.hostKey)
if hostKey == nil {
return nil, errors.New("ssh: internal error: negotiated unsupported signature type")
}
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.algorithms.hostKey)
return r, err return r, err
} }
func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { func (t *handshakeTransport) client(kex kexAlgorithm, magics *handshakeMagics) (*kexResult, error) {
result, err := kex.Client(t.conn, t.config.Rand, magics) result, err := kex.Client(t.conn, t.config.Rand, magics)
if err != nil { if err != nil {
return nil, err return nil, err
@ -655,7 +691,7 @@ func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *
return nil, err return nil, err
} }
if err := verifyHostKeySignature(hostKey, algs.hostKey, result); err != nil { if err := verifyHostKeySignature(hostKey, t.algorithms.hostKey, result); err != nil {
return nil, err return nil, err
} }

170
vendor/golang.org/x/crypto/ssh/kex.go generated vendored
View file

@ -22,10 +22,12 @@ import (
const ( const (
kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
kexAlgoDH14SHA256 = "diffie-hellman-group14-sha256"
kexAlgoECDH256 = "ecdh-sha2-nistp256" kexAlgoECDH256 = "ecdh-sha2-nistp256"
kexAlgoECDH384 = "ecdh-sha2-nistp384" kexAlgoECDH384 = "ecdh-sha2-nistp384"
kexAlgoECDH521 = "ecdh-sha2-nistp521" kexAlgoECDH521 = "ecdh-sha2-nistp521"
kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" kexAlgoCurve25519SHA256LibSSH = "curve25519-sha256@libssh.org"
kexAlgoCurve25519SHA256 = "curve25519-sha256"
// For the following kex only the client half contains a production // For the following kex only the client half contains a production
// ready implementation. The server half only consists of a minimal // ready implementation. The server half only consists of a minimal
@ -75,8 +77,9 @@ func (m *handshakeMagics) write(w io.Writer) {
// kexAlgorithm abstracts different key exchange algorithms. // kexAlgorithm abstracts different key exchange algorithms.
type kexAlgorithm interface { type kexAlgorithm interface {
// Server runs server-side key agreement, signing the result // Server runs server-side key agreement, signing the result
// with a hostkey. // with a hostkey. algo is the negotiated algorithm, and may
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) // be a certificate type.
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s AlgorithmSigner, algo string) (*kexResult, error)
// Client runs the client-side key agreement. Caller is // Client runs the client-side key agreement. Caller is
// responsible for verifying the host key signature. // responsible for verifying the host key signature.
@ -86,6 +89,7 @@ type kexAlgorithm interface {
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
type dhGroup struct { type dhGroup struct {
g, p, pMinus1 *big.Int g, p, pMinus1 *big.Int
hashFunc crypto.Hash
} }
func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
@ -96,8 +100,6 @@ func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int,
} }
func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
hashFunc := crypto.SHA1
var x *big.Int var x *big.Int
for { for {
var err error var err error
@ -132,7 +134,7 @@ func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha
return nil, err return nil, err
} }
h := hashFunc.New() h := group.hashFunc.New()
magics.write(h) magics.write(h)
writeString(h, kexDHReply.HostKey) writeString(h, kexDHReply.HostKey)
writeInt(h, X) writeInt(h, X)
@ -146,12 +148,11 @@ func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha
K: K, K: K,
HostKey: kexDHReply.HostKey, HostKey: kexDHReply.HostKey,
Signature: kexDHReply.Signature, Signature: kexDHReply.Signature,
Hash: crypto.SHA1, Hash: group.hashFunc,
}, nil }, nil
} }
func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
hashFunc := crypto.SHA1
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return return
@ -179,7 +180,7 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha
hostKeyBytes := priv.PublicKey().Marshal() hostKeyBytes := priv.PublicKey().Marshal()
h := hashFunc.New() h := group.hashFunc.New()
magics.write(h) magics.write(h)
writeString(h, hostKeyBytes) writeString(h, hostKeyBytes)
writeInt(h, kexDHInit.X) writeInt(h, kexDHInit.X)
@ -193,7 +194,7 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha
// H is already a hash, but the hostkey signing will apply its // H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm. // own key-specific hash algorithm.
sig, err := signAndMarshal(priv, randSource, H) sig, err := signAndMarshal(priv, randSource, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -211,7 +212,7 @@ func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handsha
K: K, K: K,
HostKey: hostKeyBytes, HostKey: hostKeyBytes,
Signature: sig, Signature: sig,
Hash: crypto.SHA1, Hash: group.hashFunc,
}, err }, err
} }
@ -314,7 +315,7 @@ func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
return true return true
} }
func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return nil, err return nil, err
@ -359,7 +360,7 @@ func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, p
// H is already a hash, but the hostkey signing will apply its // H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm. // own key-specific hash algorithm.
sig, err := signAndMarshal(priv, rand, H) sig, err := signAndMarshal(priv, rand, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -384,39 +385,62 @@ func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, p
}, nil }, nil
} }
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case bitSize <= 384:
return crypto.SHA384
}
return crypto.SHA512
}
var kexAlgoMap = map[string]kexAlgorithm{} var kexAlgoMap = map[string]kexAlgorithm{}
func init() { func init() {
// This is the group called diffie-hellman-group1-sha1 in RFC // This is the group called diffie-hellman-group1-sha1 in
// 4253 and Oakley Group 2 in RFC 2409. // RFC 4253 and Oakley Group 2 in RFC 2409.
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2), g: new(big.Int).SetInt64(2),
p: p, p: p,
pMinus1: new(big.Int).Sub(p, bigOne), pMinus1: new(big.Int).Sub(p, bigOne),
hashFunc: crypto.SHA1,
} }
// This is the group called diffie-hellman-group14-sha1 in RFC // This are the groups called diffie-hellman-group14-sha1 and
// 4253 and Oakley Group 14 in RFC 3526. // diffie-hellman-group14-sha256 in RFC 4253 and RFC 8268,
// and Oakley Group 14 in RFC 3526.
p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
group14 := &dhGroup{
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
g: new(big.Int).SetInt64(2), g: new(big.Int).SetInt64(2),
p: p, p: p,
pMinus1: new(big.Int).Sub(p, bigOne), pMinus1: new(big.Int).Sub(p, bigOne),
} }
kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
hashFunc: crypto.SHA1,
}
kexAlgoMap[kexAlgoDH14SHA256] = &dhGroup{
g: group14.g, p: group14.p, pMinus1: group14.pMinus1,
hashFunc: crypto.SHA256,
}
kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
kexAlgoMap[kexAlgoCurve25519SHA256LibSSH] = &curve25519sha256{}
kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1} kexAlgoMap[kexAlgoDHGEXSHA1] = &dhGEXSHA{hashFunc: crypto.SHA1}
kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256} kexAlgoMap[kexAlgoDHGEXSHA256] = &dhGEXSHA{hashFunc: crypto.SHA256}
} }
// curve25519sha256 implements the curve25519-sha256@libssh.org key // curve25519sha256 implements the curve25519-sha256 (formerly known as
// agreement protocol, as described in // curve25519-sha256@libssh.org) key exchange method, as described in RFC 8731.
// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
type curve25519sha256 struct{} type curve25519sha256 struct{}
type curve25519KeyPair struct { type curve25519KeyPair struct {
@ -486,7 +510,7 @@ func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handsh
}, nil }, nil
} }
func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return return
@ -527,7 +551,7 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh
H := h.Sum(nil) H := h.Sum(nil)
sig, err := signAndMarshal(priv, rand, H) sig, err := signAndMarshal(priv, rand, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -553,7 +577,6 @@ func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handsh
// diffie-hellman-group-exchange-sha256 key agreement protocols, // diffie-hellman-group-exchange-sha256 key agreement protocols,
// as described in RFC 4419 // as described in RFC 4419
type dhGEXSHA struct { type dhGEXSHA struct {
g, p *big.Int
hashFunc crypto.Hash hashFunc crypto.Hash
} }
@ -563,14 +586,7 @@ const (
dhGroupExchangeMaximumBits = 8192 dhGroupExchangeMaximumBits = 8192
) )
func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
if theirPublic.Sign() <= 0 || theirPublic.Cmp(gex.p) >= 0 {
return nil, fmt.Errorf("ssh: DH parameter out of bounds")
}
return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil
}
func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
// Send GexRequest // Send GexRequest
kexDHGexRequest := kexDHGexRequestMsg{ kexDHGexRequest := kexDHGexRequestMsg{
MinBits: dhGroupExchangeMinimumBits, MinBits: dhGroupExchangeMinimumBits,
@ -587,35 +603,29 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
return nil, err return nil, err
} }
var kexDHGexGroup kexDHGexGroupMsg var msg kexDHGexGroupMsg
if err = Unmarshal(packet, &kexDHGexGroup); err != nil { if err = Unmarshal(packet, &msg); err != nil {
return nil, err return nil, err
} }
// reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits // reject if p's bit length < dhGroupExchangeMinimumBits or > dhGroupExchangeMaximumBits
if kexDHGexGroup.P.BitLen() < dhGroupExchangeMinimumBits || kexDHGexGroup.P.BitLen() > dhGroupExchangeMaximumBits { if msg.P.BitLen() < dhGroupExchangeMinimumBits || msg.P.BitLen() > dhGroupExchangeMaximumBits {
return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", kexDHGexGroup.P.BitLen()) return nil, fmt.Errorf("ssh: server-generated gex p is out of range (%d bits)", msg.P.BitLen())
} }
gex.p = kexDHGexGroup.P // Check if g is safe by verifying that 1 < g < p-1
gex.g = kexDHGexGroup.G pMinusOne := new(big.Int).Sub(msg.P, bigOne)
if msg.G.Cmp(bigOne) <= 0 || msg.G.Cmp(pMinusOne) >= 0 {
// Check if g is safe by verifing that g > 1 and g < p - 1
one := big.NewInt(1)
var pMinusOne = &big.Int{}
pMinusOne.Sub(gex.p, one)
if gex.g.Cmp(one) != 1 && gex.g.Cmp(pMinusOne) != -1 {
return nil, fmt.Errorf("ssh: server provided gex g is not safe") return nil, fmt.Errorf("ssh: server provided gex g is not safe")
} }
// Send GexInit // Send GexInit
var pHalf = &big.Int{} pHalf := new(big.Int).Rsh(msg.P, 1)
pHalf.Rsh(gex.p, 1)
x, err := rand.Int(randSource, pHalf) x, err := rand.Int(randSource, pHalf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
X := new(big.Int).Exp(gex.g, x, gex.p) X := new(big.Int).Exp(msg.G, x, msg.P)
kexDHGexInit := kexDHGexInitMsg{ kexDHGexInit := kexDHGexInitMsg{
X: X, X: X,
} }
@ -634,13 +644,13 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
return nil, err return nil, err
} }
kInt, err := gex.diffieHellman(kexDHGexReply.Y, x) if kexDHGexReply.Y.Cmp(bigOne) <= 0 || kexDHGexReply.Y.Cmp(pMinusOne) >= 0 {
if err != nil { return nil, errors.New("ssh: DH parameter out of bounds")
return nil, err
} }
kInt := new(big.Int).Exp(kexDHGexReply.Y, x, msg.P)
// Check if k is safe by verifing that k > 1 and k < p - 1 // Check if k is safe by verifying that k > 1 and k < p - 1
if kInt.Cmp(one) != 1 && kInt.Cmp(pMinusOne) != -1 { if kInt.Cmp(bigOne) <= 0 || kInt.Cmp(pMinusOne) >= 0 {
return nil, fmt.Errorf("ssh: derived k is not safe") return nil, fmt.Errorf("ssh: derived k is not safe")
} }
@ -650,8 +660,8 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
writeInt(h, gex.p) writeInt(h, msg.P)
writeInt(h, gex.g) writeInt(h, msg.G)
writeInt(h, X) writeInt(h, X)
writeInt(h, kexDHGexReply.Y) writeInt(h, kexDHGexReply.Y)
K := make([]byte, intLength(kInt)) K := make([]byte, intLength(kInt))
@ -670,7 +680,7 @@ func (gex dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshake
// Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256. // Server half implementation of the Diffie Hellman Key Exchange with SHA1 and SHA256.
// //
// This is a minimal implementation to satisfy the automated tests. // This is a minimal implementation to satisfy the automated tests.
func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv AlgorithmSigner, algo string) (result *kexResult, err error) {
// Receive GexRequest // Receive GexRequest
packet, err := c.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
@ -681,35 +691,17 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
return return
} }
// smoosh the user's preferred size into our own limits
if kexDHGexRequest.PreferedBits > dhGroupExchangeMaximumBits {
kexDHGexRequest.PreferedBits = dhGroupExchangeMaximumBits
}
if kexDHGexRequest.PreferedBits < dhGroupExchangeMinimumBits {
kexDHGexRequest.PreferedBits = dhGroupExchangeMinimumBits
}
// fix min/max if they're inconsistent. technically, we could just pout
// and hang up, but there's no harm in giving them the benefit of the
// doubt and just picking a bitsize for them.
if kexDHGexRequest.MinBits > kexDHGexRequest.PreferedBits {
kexDHGexRequest.MinBits = kexDHGexRequest.PreferedBits
}
if kexDHGexRequest.MaxBits < kexDHGexRequest.PreferedBits {
kexDHGexRequest.MaxBits = kexDHGexRequest.PreferedBits
}
// Send GexGroup // Send GexGroup
// This is the group called diffie-hellman-group14-sha1 in RFC // This is the group called diffie-hellman-group14-sha1 in RFC
// 4253 and Oakley Group 14 in RFC 3526. // 4253 and Oakley Group 14 in RFC 3526.
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
gex.p = p g := big.NewInt(2)
gex.g = big.NewInt(2)
kexDHGexGroup := kexDHGexGroupMsg{ msg := &kexDHGexGroupMsg{
P: gex.p, P: p,
G: gex.g, G: g,
} }
if err := c.writePacket(Marshal(&kexDHGexGroup)); err != nil { if err := c.writePacket(Marshal(msg)); err != nil {
return nil, err return nil, err
} }
@ -723,19 +715,19 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
return return
} }
var pHalf = &big.Int{} pHalf := new(big.Int).Rsh(p, 1)
pHalf.Rsh(gex.p, 1)
y, err := rand.Int(randSource, pHalf) y, err := rand.Int(randSource, pHalf)
if err != nil { if err != nil {
return return
} }
Y := new(big.Int).Exp(g, y, p)
Y := new(big.Int).Exp(gex.g, y, gex.p) pMinusOne := new(big.Int).Sub(p, bigOne)
kInt, err := gex.diffieHellman(kexDHGexInit.X, y) if kexDHGexInit.X.Cmp(bigOne) <= 0 || kexDHGexInit.X.Cmp(pMinusOne) >= 0 {
if err != nil { return nil, errors.New("ssh: DH parameter out of bounds")
return nil, err
} }
kInt := new(big.Int).Exp(kexDHGexInit.X, y, p)
hostKeyBytes := priv.PublicKey().Marshal() hostKeyBytes := priv.PublicKey().Marshal()
@ -745,8 +737,8 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMinimumBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangePreferredBits))
binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits)) binary.Write(h, binary.BigEndian, uint32(dhGroupExchangeMaximumBits))
writeInt(h, gex.p) writeInt(h, p)
writeInt(h, gex.g) writeInt(h, g)
writeInt(h, kexDHGexInit.X) writeInt(h, kexDHGexInit.X)
writeInt(h, Y) writeInt(h, Y)
@ -758,7 +750,7 @@ func (gex dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshake
// H is already a hash, but the hostkey signing will apply its // H is already a hash, but the hostkey signing will apply its
// own key-specific hash algorithm. // own key-specific hash algorithm.
sig, err := signAndMarshal(priv, randSource, H) sig, err := signAndMarshal(priv, randSource, H, algo)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -30,8 +30,9 @@ import (
"golang.org/x/crypto/ssh/internal/bcrypt_pbkdf" "golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
) )
// These constants represent the algorithm names for key types supported by this // Public key algorithms names. These values can appear in PublicKey.Type,
// package. // ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner
// arguments.
const ( const (
KeyAlgoRSA = "ssh-rsa" KeyAlgoRSA = "ssh-rsa"
KeyAlgoDSA = "ssh-dss" KeyAlgoDSA = "ssh-dss"
@ -41,16 +42,21 @@ const (
KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
KeyAlgoED25519 = "ssh-ed25519" KeyAlgoED25519 = "ssh-ed25519"
KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com" KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
// KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not
// public key formats, so they can't appear as a PublicKey.Type. The
// corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2.
KeyAlgoRSASHA256 = "rsa-sha2-256"
KeyAlgoRSASHA512 = "rsa-sha2-512"
) )
// These constants represent non-default signature algorithms that are supported
// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See
// [PROTOCOL.agent] section 4.5.1 and
// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10
const ( const (
SigAlgoRSA = "ssh-rsa" // Deprecated: use KeyAlgoRSA.
SigAlgoRSASHA2256 = "rsa-sha2-256" SigAlgoRSA = KeyAlgoRSA
SigAlgoRSASHA2512 = "rsa-sha2-512" // Deprecated: use KeyAlgoRSASHA256.
SigAlgoRSASHA2256 = KeyAlgoRSASHA256
// Deprecated: use KeyAlgoRSASHA512.
SigAlgoRSASHA2512 = KeyAlgoRSASHA512
) )
// parsePubKey parses a public key of the given algorithm. // parsePubKey parses a public key of the given algorithm.
@ -70,7 +76,7 @@ func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err err
case KeyAlgoSKED25519: case KeyAlgoSKED25519:
return parseSKEd25519(in) return parseSKEd25519(in)
case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
cert, err := parseCert(in, certToPrivAlgo(algo)) cert, err := parseCert(in, certKeyAlgoNames[algo])
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -178,7 +184,7 @@ func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey
return "", nil, nil, "", nil, io.EOF return "", nil, nil, "", nil, io.EOF
} }
// ParseAuthorizedKeys parses a public key from an authorized_keys // ParseAuthorizedKey parses a public key from an authorized_keys
// file used in OpenSSH according to the sshd(8) manual page. // file used in OpenSSH according to the sshd(8) manual page.
func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
for len(in) > 0 { for len(in) > 0 {
@ -289,18 +295,21 @@ func MarshalAuthorizedKey(key PublicKey) []byte {
return b.Bytes() return b.Bytes()
} }
// PublicKey is an abstraction of different types of public keys. // PublicKey represents a public key using an unspecified algorithm.
//
// Some PublicKeys provided by this package also implement CryptoPublicKey.
type PublicKey interface { type PublicKey interface {
// Type returns the key's type, e.g. "ssh-rsa". // Type returns the key format name, e.g. "ssh-rsa".
Type() string Type() string
// Marshal returns the serialized key data in SSH wire format, // Marshal returns the serialized key data in SSH wire format, with the name
// with the name prefix. To unmarshal the returned data, use // prefix. To unmarshal the returned data, use the ParsePublicKey function.
// the ParsePublicKey function.
Marshal() []byte Marshal() []byte
// Verify that sig is a signature on the given data using this // Verify that sig is a signature on the given data using this key. This
// key. This function will hash the data appropriately first. // method will hash the data appropriately first. sig.Format is allowed to
// be any signature algorithm compatible with the key type, the caller
// should check if it has more stringent requirements.
Verify(data []byte, sig *Signature) error Verify(data []byte, sig *Signature) error
} }
@ -311,25 +320,32 @@ type CryptoPublicKey interface {
} }
// A Signer can create signatures that verify against a public key. // A Signer can create signatures that verify against a public key.
//
// Some Signers provided by this package also implement AlgorithmSigner.
type Signer interface { type Signer interface {
// PublicKey returns an associated PublicKey instance. // PublicKey returns the associated PublicKey.
PublicKey() PublicKey PublicKey() PublicKey
// Sign returns raw signature for the given data. This method // Sign returns a signature for the given data. This method will hash the
// will apply the hash specified for the keytype to the data. // data appropriately first. The signature algorithm is expected to match
// the key format returned by the PublicKey.Type method (and not to be any
// alternative algorithm supported by the key format).
Sign(rand io.Reader, data []byte) (*Signature, error) Sign(rand io.Reader, data []byte) (*Signature, error)
} }
// A AlgorithmSigner is a Signer that also supports specifying a specific // An AlgorithmSigner is a Signer that also supports specifying an algorithm to
// algorithm to use for signing. // use for signing.
//
// An AlgorithmSigner can't advertise the algorithms it supports, so it should
// be prepared to be invoked with every algorithm supported by the public key
// format.
type AlgorithmSigner interface { type AlgorithmSigner interface {
Signer Signer
// SignWithAlgorithm is like Signer.Sign, but allows specification of a // SignWithAlgorithm is like Signer.Sign, but allows specifying a desired
// non-default signing algorithm. See the SigAlgo* constants in this // signing algorithm. Callers may pass an empty string for the algorithm in
// package for signature algorithms supported by this package. Callers may // which case the AlgorithmSigner will use a default algorithm. This default
// pass an empty string for the algorithm in which case the AlgorithmSigner // doesn't currently control any behavior in this package.
// will use its default algorithm.
SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
} }
@ -381,17 +397,11 @@ func (r *rsaPublicKey) Marshal() []byte {
} }
func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
var hash crypto.Hash supportedAlgos := algorithmsForKeyFormat(r.Type())
switch sig.Format { if !contains(supportedAlgos, sig.Format) {
case SigAlgoRSA:
hash = crypto.SHA1
case SigAlgoRSASHA2256:
hash = crypto.SHA256
case SigAlgoRSASHA2512:
hash = crypto.SHA512
default:
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
} }
hash := hashFuncs[sig.Format]
h := hash.New() h := hash.New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
@ -466,7 +476,7 @@ func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
if sig.Format != k.Type() { if sig.Format != k.Type() {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
} }
h := crypto.SHA1.New() h := hashFuncs[sig.Format].New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
@ -499,7 +509,7 @@ func (k *dsaPrivateKey) PublicKey() PublicKey {
} }
func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
return k.SignWithAlgorithm(rand, data, "") return k.SignWithAlgorithm(rand, data, k.PublicKey().Type())
} }
func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
@ -507,7 +517,7 @@ func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
} }
h := crypto.SHA1.New() h := hashFuncs[k.PublicKey().Type()].New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
r, s, err := dsa.Sign(rand, k.PrivateKey, digest) r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
@ -603,19 +613,6 @@ func supportedEllipticCurve(curve elliptic.Curve) bool {
return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
} }
// ecHash returns the hash to match the given elliptic curve, see RFC
// 5656, section 6.2.1
func ecHash(curve elliptic.Curve) crypto.Hash {
bitSize := curve.Params().BitSize
switch {
case bitSize <= 256:
return crypto.SHA256
case bitSize <= 384:
return crypto.SHA384
}
return crypto.SHA512
}
// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. // parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
var w struct { var w struct {
@ -671,7 +668,7 @@ func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
} }
h := ecHash(k.Curve).New() h := hashFuncs[sig.Format].New()
h.Write(data) h.Write(data)
digest := h.Sum(nil) digest := h.Sum(nil)
@ -775,7 +772,7 @@ func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
} }
h := ecHash(k.Curve).New() h := hashFuncs[sig.Format].New()
h.Write([]byte(k.application)) h.Write([]byte(k.application))
appDigest := h.Sum(nil) appDigest := h.Sum(nil)
@ -874,7 +871,7 @@ func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
return fmt.Errorf("invalid size %d for Ed25519 public key", l) return fmt.Errorf("invalid size %d for Ed25519 public key", l)
} }
h := sha256.New() h := hashFuncs[sig.Format].New()
h.Write([]byte(k.application)) h.Write([]byte(k.application))
appDigest := h.Sum(nil) appDigest := h.Sum(nil)
@ -939,15 +936,6 @@ func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) {
return &dsaPrivateKey{key}, nil return &dsaPrivateKey{key}, nil
} }
type rsaSigner struct {
AlgorithmSigner
defaultAlgorithm string
}
func (s *rsaSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.AlgorithmSigner.SignWithAlgorithm(rand, data, s.defaultAlgorithm)
}
type wrappedSigner struct { type wrappedSigner struct {
signer crypto.Signer signer crypto.Signer
pubKey PublicKey pubKey PublicKey
@ -970,44 +958,20 @@ func (s *wrappedSigner) PublicKey() PublicKey {
} }
func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
return s.SignWithAlgorithm(rand, data, "") return s.SignWithAlgorithm(rand, data, s.pubKey.Type())
} }
func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
var hashFunc crypto.Hash
if _, ok := s.pubKey.(*rsaPublicKey); ok {
// RSA keys support a few hash functions determined by the requested signature algorithm
switch algorithm {
case "", SigAlgoRSA:
algorithm = SigAlgoRSA
hashFunc = crypto.SHA1
case SigAlgoRSASHA2256:
hashFunc = crypto.SHA256
case SigAlgoRSASHA2512:
hashFunc = crypto.SHA512
default:
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
}
} else {
// The only supported algorithm for all other key types is the same as the type of the key
if algorithm == "" { if algorithm == "" {
algorithm = s.pubKey.Type() algorithm = s.pubKey.Type()
} else if algorithm != s.pubKey.Type() {
return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
} }
switch key := s.pubKey.(type) { supportedAlgos := algorithmsForKeyFormat(s.pubKey.Type())
case *dsaPublicKey: if !contains(supportedAlgos, algorithm) {
hashFunc = crypto.SHA1 return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
case *ecdsaPublicKey:
hashFunc = ecHash(key.Curve)
case ed25519PublicKey:
default:
return nil, fmt.Errorf("ssh: unsupported key type %T", key)
}
} }
hashFunc := hashFuncs[algorithm]
var digest []byte var digest []byte
if hashFunc != 0 { if hashFunc != 0 {
h := hashFunc.New() h := hashFunc.New()

View file

@ -141,6 +141,14 @@ type serviceAcceptMsg struct {
Service string `sshtype:"6"` Service string `sshtype:"6"`
} }
// See RFC 8308, section 2.3
const msgExtInfo = 7
type extInfoMsg struct {
NumExtensions uint32 `sshtype:"7"`
Payload []byte `ssh:"rest"`
}
// See RFC 4252, section 5. // See RFC 4252, section 5.
const msgUserAuthRequest = 50 const msgUserAuthRequest = 50
@ -180,9 +188,9 @@ const msgUserAuthInfoRequest = 60
const msgUserAuthInfoResponse = 61 const msgUserAuthInfoResponse = 61
type userAuthInfoRequestMsg struct { type userAuthInfoRequestMsg struct {
User string `sshtype:"60"` Name string `sshtype:"60"`
Instruction string Instruction string
DeprecatedLanguage string Language string
NumPrompts uint32 NumPrompts uint32
Prompts []byte `ssh:"rest"` Prompts []byte `ssh:"rest"`
} }
@ -782,6 +790,8 @@ func decode(packet []byte) (interface{}, error) {
msg = new(serviceRequestMsg) msg = new(serviceRequestMsg)
case msgServiceAccept: case msgServiceAccept:
msg = new(serviceAcceptMsg) msg = new(serviceAcceptMsg)
case msgExtInfo:
msg = new(extInfoMsg)
case msgKexInit: case msgKexInit:
msg = new(kexInitMsg) msg = new(kexInitMsg)
case msgKexDHInit: case msgKexDHInit:
@ -843,6 +853,7 @@ var packetTypeNames = map[byte]string{
msgDisconnect: "disconnectMsg", msgDisconnect: "disconnectMsg",
msgServiceRequest: "serviceRequestMsg", msgServiceRequest: "serviceRequestMsg",
msgServiceAccept: "serviceAcceptMsg", msgServiceAccept: "serviceAcceptMsg",
msgExtInfo: "extInfoMsg",
msgKexInit: "kexInitMsg", msgKexInit: "kexInitMsg",
msgKexDHInit: "kexDHInitMsg", msgKexDHInit: "kexDHInitMsg",
msgKexDHReply: "kexDHReplyMsg", msgKexDHReply: "kexDHReplyMsg",

View file

@ -68,8 +68,16 @@ type ServerConfig struct {
// NoClientAuth is true if clients are allowed to connect without // NoClientAuth is true if clients are allowed to connect without
// authenticating. // authenticating.
// To determine NoClientAuth at runtime, set NoClientAuth to true
// and the optional NoClientAuthCallback to a non-nil value.
NoClientAuth bool NoClientAuth bool
// NoClientAuthCallback, if non-nil, is called when a user
// attempts to authenticate with auth method "none".
// NoClientAuth must also be set to true for this be used, or
// this func is unused.
NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
// MaxAuthTries specifies the maximum number of authentication attempts // MaxAuthTries specifies the maximum number of authentication attempts
// permitted per connection. If set to a negative number, the number of // permitted per connection. If set to a negative number, the number of
// attempts are unlimited. If set to zero, the number of attempts are limited // attempts are unlimited. If set to zero, the number of attempts are limited
@ -120,7 +128,7 @@ type ServerConfig struct {
} }
// AddHostKey adds a private key as a host key. If an existing host // AddHostKey adds a private key as a host key. If an existing host
// key exists with the same algorithm, it is overwritten. Each server // key exists with the same public key format, it is replaced. Each server
// config must have at least one host key. // config must have at least one host key.
func (s *ServerConfig) AddHostKey(key Signer) { func (s *ServerConfig) AddHostKey(key Signer) {
for i, k := range s.hostKeys { for i, k := range s.hostKeys {
@ -212,9 +220,10 @@ func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewCha
} }
// signAndMarshal signs the data with the appropriate algorithm, // signAndMarshal signs the data with the appropriate algorithm,
// and serializes the result in SSH wire format. // and serializes the result in SSH wire format. algo is the negotiate
func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { // algorithm and may be a certificate type.
sig, err := k.Sign(rand, data) func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -284,7 +293,7 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error)
func isAcceptableAlgo(algo string) bool { func isAcceptableAlgo(algo string) bool {
switch algo { switch algo {
case SigAlgoRSA, SigAlgoRSASHA2256, SigAlgoRSASHA2512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519, case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519,
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
return true return true
} }
@ -454,8 +463,12 @@ userAuthLoop:
switch userAuthReq.Method { switch userAuthReq.Method {
case "none": case "none":
if config.NoClientAuth { if config.NoClientAuth {
if config.NoClientAuthCallback != nil {
perms, authErr = config.NoClientAuthCallback(s)
} else {
authErr = nil authErr = nil
} }
}
// allow initial attempt of 'none' without penalty // allow initial attempt of 'none' without penalty
if authFailures == 0 { if authFailures == 0 {
@ -553,6 +566,7 @@ userAuthLoop:
if !ok || len(payload) > 0 { if !ok || len(payload) > 0 {
return nil, parseError(msgUserAuthRequest) return nil, parseError(msgUserAuthRequest)
} }
// Ensure the public key algo and signature algo // Ensure the public key algo and signature algo
// are supported. Compare the private key // are supported. Compare the private key
// algorithm name that corresponds to algo with // algorithm name that corresponds to algo with
@ -562,7 +576,12 @@ userAuthLoop:
authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
break break
} }
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) if underlyingAlgo(algo) != sig.Format {
authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
break
}
signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
if err := pubKey.Verify(signedData, sig); err != nil { if err := pubKey.Verify(signedData, sig); err != nil {
return nil, err return nil, err
@ -633,6 +652,30 @@ userAuthLoop:
} }
authFailures++ authFailures++
if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
// If we have hit the max attempts, don't bother sending the
// final SSH_MSG_USERAUTH_FAILURE message, since there are
// no more authentication methods which can be attempted,
// and this message may cause the client to re-attempt
// authentication while we send the disconnect message.
// Continue, and trigger the disconnect at the start of
// the loop.
//
// The SSH specification is somewhat confusing about this,
// RFC 4252 Section 5.1 requires each authentication failure
// be responded to with a respective SSH_MSG_USERAUTH_FAILURE
// message, but Section 4 says the server should disconnect
// after some number of attempts, but it isn't explicit which
// message should take precedence (i.e. should there be a failure
// message than a disconnect message, or if we are going to
// disconnect, should we only send that message.)
//
// Either way, OpenSSH disconnects immediately after the last
// failed authnetication attempt, and given they are typically
// considered the golden implementation it seems reasonable
// to match that behavior.
continue
}
var failureMsg userAuthFailureMsg var failureMsg userAuthFailureMsg
if config.PasswordCallback != nil { if config.PasswordCallback != nil {
@ -670,7 +713,7 @@ type sshClientKeyboardInteractive struct {
*connection *connection
} }
func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
if len(questions) != len(echos) { if len(questions) != len(echos) {
return nil, errors.New("ssh: echos and questions must have equal length") return nil, errors.New("ssh: echos and questions must have equal length")
} }
@ -682,6 +725,7 @@ func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, quest
} }
if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
Name: name,
Instruction: instruction, Instruction: instruction,
NumPrompts: uint32(len(questions)), NumPrompts: uint32(len(questions)),
Prompts: prompts, Prompts: prompts,

View file

@ -13,7 +13,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"sync" "sync"
) )
@ -85,6 +84,7 @@ const (
IXANY = 39 IXANY = 39
IXOFF = 40 IXOFF = 40
IMAXBEL = 41 IMAXBEL = 41
IUTF8 = 42 // RFC 8160
ISIG = 50 ISIG = 50
ICANON = 51 ICANON = 51
XCASE = 52 XCASE = 52
@ -123,7 +123,7 @@ type Session struct {
// output and error. // output and error.
// //
// If either is nil, Run connects the corresponding file // If either is nil, Run connects the corresponding file
// descriptor to an instance of ioutil.Discard. There is a // descriptor to an instance of io.Discard. There is a
// fixed amount of buffering that is shared for the two streams. // fixed amount of buffering that is shared for the two streams.
// If either blocks it may eventually cause the remote // If either blocks it may eventually cause the remote
// command to block. // command to block.
@ -505,7 +505,7 @@ func (s *Session) stdout() {
return return
} }
if s.Stdout == nil { if s.Stdout == nil {
s.Stdout = ioutil.Discard s.Stdout = io.Discard
} }
s.copyFuncs = append(s.copyFuncs, func() error { s.copyFuncs = append(s.copyFuncs, func() error {
_, err := io.Copy(s.Stdout, s.ch) _, err := io.Copy(s.Stdout, s.ch)
@ -518,7 +518,7 @@ func (s *Session) stderr() {
return return
} }
if s.Stderr == nil { if s.Stderr == nil {
s.Stderr = ioutil.Discard s.Stderr = io.Discard
} }
s.copyFuncs = append(s.copyFuncs, func() error { s.copyFuncs = append(s.copyFuncs, func() error {
_, err := io.Copy(s.Stderr, s.ch.Stderr()) _, err := io.Copy(s.Stderr, s.ch.Stderr())

View file

@ -238,15 +238,19 @@ var (
// (to setup server->client keys) or clientKeys (for client->server keys). // (to setup server->client keys) or clientKeys (for client->server keys).
func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
cipherMode := cipherModes[algs.Cipher] cipherMode := cipherModes[algs.Cipher]
macMode := macModes[algs.MAC]
iv := make([]byte, cipherMode.ivSize) iv := make([]byte, cipherMode.ivSize)
key := make([]byte, cipherMode.keySize) key := make([]byte, cipherMode.keySize)
macKey := make([]byte, macMode.keySize)
generateKeyMaterial(iv, d.ivTag, kex) generateKeyMaterial(iv, d.ivTag, kex)
generateKeyMaterial(key, d.keyTag, kex) generateKeyMaterial(key, d.keyTag, kex)
var macKey []byte
if !aeadCiphers[algs.Cipher] {
macMode := macModes[algs.MAC]
macKey = make([]byte, macMode.keySize)
generateKeyMaterial(macKey, d.macKeyTag, kex) generateKeyMaterial(macKey, d.macKeyTag, kex)
}
return cipherModes[algs.Cipher].create(key, iv, macKey, algs) return cipherModes[algs.Cipher].create(key, iv, macKey, algs)
} }

View file

@ -22,6 +22,8 @@
// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0. // as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
package semver package semver
import "sort"
// parsed returns the parsed form of a semantic version string. // parsed returns the parsed form of a semantic version string.
type parsed struct { type parsed struct {
major string major string
@ -30,7 +32,6 @@ type parsed struct {
short string short string
prerelease string prerelease string
build string build string
err string
} }
// IsValid reports whether v is a valid semantic version string. // IsValid reports whether v is a valid semantic version string.
@ -150,14 +151,30 @@ func Max(v, w string) string {
return w return w
} }
// ByVersion implements sort.Interface for sorting semantic version strings.
type ByVersion []string
func (vs ByVersion) Len() int { return len(vs) }
func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
func (vs ByVersion) Less(i, j int) bool {
cmp := Compare(vs[i], vs[j])
if cmp != 0 {
return cmp < 0
}
return vs[i] < vs[j]
}
// Sort sorts a list of semantic version strings using ByVersion.
func Sort(list []string) {
sort.Sort(ByVersion(list))
}
func parse(v string) (p parsed, ok bool) { func parse(v string) (p parsed, ok bool) {
if v == "" || v[0] != 'v' { if v == "" || v[0] != 'v' {
p.err = "missing v prefix"
return return
} }
p.major, v, ok = parseInt(v[1:]) p.major, v, ok = parseInt(v[1:])
if !ok { if !ok {
p.err = "bad major version"
return return
} }
if v == "" { if v == "" {
@ -167,13 +184,11 @@ func parse(v string) (p parsed, ok bool) {
return return
} }
if v[0] != '.' { if v[0] != '.' {
p.err = "bad minor prefix"
ok = false ok = false
return return
} }
p.minor, v, ok = parseInt(v[1:]) p.minor, v, ok = parseInt(v[1:])
if !ok { if !ok {
p.err = "bad minor version"
return return
} }
if v == "" { if v == "" {
@ -182,31 +197,26 @@ func parse(v string) (p parsed, ok bool) {
return return
} }
if v[0] != '.' { if v[0] != '.' {
p.err = "bad patch prefix"
ok = false ok = false
return return
} }
p.patch, v, ok = parseInt(v[1:]) p.patch, v, ok = parseInt(v[1:])
if !ok { if !ok {
p.err = "bad patch version"
return return
} }
if len(v) > 0 && v[0] == '-' { if len(v) > 0 && v[0] == '-' {
p.prerelease, v, ok = parsePrerelease(v) p.prerelease, v, ok = parsePrerelease(v)
if !ok { if !ok {
p.err = "bad prerelease"
return return
} }
} }
if len(v) > 0 && v[0] == '+' { if len(v) > 0 && v[0] == '+' {
p.build, v, ok = parseBuild(v) p.build, v, ok = parseBuild(v)
if !ok { if !ok {
p.err = "bad build"
return return
} }
} }
if v != "" { if v != "" {
p.err = "junk on end"
ok = false ok = false
return return
} }

3
vendor/golang.org/x/net/AUTHORS generated vendored
View file

@ -1,3 +0,0 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

View file

@ -1,3 +0,0 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

View file

@ -32,7 +32,7 @@ var DeadlineExceeded = context.DeadlineExceeded
// call cancel as soon as the operations running in this Context complete. // call cancel as soon as the operations running in this Context complete.
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
ctx, f := context.WithCancel(parent) ctx, f := context.WithCancel(parent)
return ctx, CancelFunc(f) return ctx, f
} }
// WithDeadline returns a copy of the parent context with the deadline adjusted // WithDeadline returns a copy of the parent context with the deadline adjusted
@ -46,7 +46,7 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
// call cancel as soon as the operations running in this Context complete. // call cancel as soon as the operations running in this Context complete.
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
ctx, f := context.WithDeadline(parent, deadline) ctx, f := context.WithDeadline(parent, deadline)
return ctx, CancelFunc(f) return ctx, f
} }
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).

View file

@ -734,7 +734,7 @@ func inHeadIM(p *parser) bool {
return false return false
} }
// 12.2.6.4.5. // Section 12.2.6.4.5.
func inHeadNoscriptIM(p *parser) bool { func inHeadNoscriptIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case DoctypeToken: case DoctypeToken:

View file

@ -85,7 +85,7 @@ func render1(w writer, n *Node) error {
if _, err := w.WriteString("<!--"); err != nil { if _, err := w.WriteString("<!--"); err != nil {
return err return err
} }
if _, err := w.WriteString(n.Data); err != nil { if err := escape(w, n.Data); err != nil {
return err return err
} }
if _, err := w.WriteString("-->"); err != nil { if _, err := w.WriteString("-->"); err != nil {
@ -96,7 +96,7 @@ func render1(w writer, n *Node) error {
if _, err := w.WriteString("<!DOCTYPE "); err != nil { if _, err := w.WriteString("<!DOCTYPE "); err != nil {
return err return err
} }
if _, err := w.WriteString(n.Data); err != nil { if err := escape(w, n.Data); err != nil {
return err return err
} }
if n.Attr != nil { if n.Attr != nil {

View file

@ -110,9 +110,9 @@ func (t Token) String() string {
case SelfClosingTagToken: case SelfClosingTagToken:
return "<" + t.tagString() + "/>" return "<" + t.tagString() + "/>"
case CommentToken: case CommentToken:
return "<!--" + t.Data + "-->" return "<!--" + EscapeString(t.Data) + "-->"
case DoctypeToken: case DoctypeToken:
return "<!DOCTYPE " + t.Data + ">" return "<!DOCTYPE " + EscapeString(t.Data) + ">"
} }
return "Invalid(" + strconv.Itoa(int(t.Type)) + ")" return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
} }

View file

@ -173,11 +173,13 @@ func tokenEqual(t1, t2 string) bool {
// isLWS reports whether b is linear white space, according // isLWS reports whether b is linear white space, according
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 // to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
//
// LWS = [CRLF] 1*( SP | HT ) // LWS = [CRLF] 1*( SP | HT )
func isLWS(b byte) bool { return b == ' ' || b == '\t' } func isLWS(b byte) bool { return b == ' ' || b == '\t' }
// isCTL reports whether b is a control byte, according // isCTL reports whether b is a control byte, according
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 // to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
//
// CTL = <any US-ASCII control character // CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)> // (octets 0 - 31) and DEL (127)>
func isCTL(b byte) bool { func isCTL(b byte) bool {
@ -190,6 +192,7 @@ func isCTL(b byte) bool {
// letters are not allowed. // letters are not allowed.
// //
// RFC 7230 says: // RFC 7230 says:
//
// header-field = field-name ":" OWS field-value OWS // header-field = field-name ":" OWS field-value OWS
// field-name = token // field-name = token
// token = 1*tchar // token = 1*tchar
@ -282,6 +285,7 @@ var validHostByte = [256]bool{
// (octets 0 - 31) and DEL (127)> // (octets 0 - 31) and DEL (127)>
// //
// RFC 7230 says: // RFC 7230 says:
//
// field-value = *( field-content / obs-fold ) // field-value = *( field-content / obs-fold )
// obj-fold = N/A to http2, and deprecated // obj-fold = N/A to http2, and deprecated
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] // field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]

View file

@ -139,7 +139,6 @@ func (p *clientConnPool) getStartDialLocked(ctx context.Context, addr string) *d
func (c *dialCall) dial(ctx context.Context, addr string) { func (c *dialCall) dial(ctx context.Context, addr string) {
const singleUse = false // shared conn const singleUse = false // shared conn
c.res, c.err = c.p.t.dialClientConn(ctx, addr, singleUse) c.res, c.err = c.p.t.dialClientConn(ctx, addr, singleUse)
close(c.done)
c.p.mu.Lock() c.p.mu.Lock()
delete(c.p.dialing, addr) delete(c.p.dialing, addr)
@ -147,6 +146,8 @@ func (c *dialCall) dial(ctx context.Context, addr string) {
c.p.addConnLocked(addr, c.res) c.p.addConnLocked(addr, c.res)
} }
c.p.mu.Unlock() c.p.mu.Unlock()
close(c.done)
} }
// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't // addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't

View file

@ -136,7 +136,7 @@ func (e headerFieldNameError) Error() string {
type headerFieldValueError string type headerFieldValueError string
func (e headerFieldValueError) Error() string { func (e headerFieldValueError) Error() string {
return fmt.Sprintf("invalid header field value %q", string(e)) return fmt.Sprintf("invalid header field value for %q", string(e))
} }
var ( var (

View file

@ -23,7 +23,7 @@ const frameHeaderLen = 9
var padZeros = make([]byte, 255) // zeros for padding var padZeros = make([]byte, 255) // zeros for padding
// A FrameType is a registered frame type as defined in // A FrameType is a registered frame type as defined in
// http://http2.github.io/http2-spec/#rfc.section.11.2 // https://httpwg.org/specs/rfc7540.html#rfc.section.11.2
type FrameType uint8 type FrameType uint8
const ( const (
@ -146,7 +146,7 @@ func typeFrameParser(t FrameType) frameParser {
// A FrameHeader is the 9 byte header of all HTTP/2 frames. // A FrameHeader is the 9 byte header of all HTTP/2 frames.
// //
// See http://http2.github.io/http2-spec/#FrameHeader // See https://httpwg.org/specs/rfc7540.html#FrameHeader
type FrameHeader struct { type FrameHeader struct {
valid bool // caller can access []byte fields in the Frame valid bool // caller can access []byte fields in the Frame
@ -575,7 +575,7 @@ func (fr *Framer) checkFrameOrder(f Frame) error {
// A DataFrame conveys arbitrary, variable-length sequences of octets // A DataFrame conveys arbitrary, variable-length sequences of octets
// associated with a stream. // associated with a stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.1 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.1
type DataFrame struct { type DataFrame struct {
FrameHeader FrameHeader
data []byte data []byte
@ -698,7 +698,7 @@ func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []by
// endpoints communicate, such as preferences and constraints on peer // endpoints communicate, such as preferences and constraints on peer
// behavior. // behavior.
// //
// See http://http2.github.io/http2-spec/#SETTINGS // See https://httpwg.org/specs/rfc7540.html#SETTINGS
type SettingsFrame struct { type SettingsFrame struct {
FrameHeader FrameHeader
p []byte p []byte
@ -837,7 +837,7 @@ func (f *Framer) WriteSettingsAck() error {
// A PingFrame is a mechanism for measuring a minimal round trip time // A PingFrame is a mechanism for measuring a minimal round trip time
// from the sender, as well as determining whether an idle connection // from the sender, as well as determining whether an idle connection
// is still functional. // is still functional.
// See http://http2.github.io/http2-spec/#rfc.section.6.7 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.7
type PingFrame struct { type PingFrame struct {
FrameHeader FrameHeader
Data [8]byte Data [8]byte
@ -870,7 +870,7 @@ func (f *Framer) WritePing(ack bool, data [8]byte) error {
} }
// A GoAwayFrame informs the remote peer to stop creating streams on this connection. // A GoAwayFrame informs the remote peer to stop creating streams on this connection.
// See http://http2.github.io/http2-spec/#rfc.section.6.8 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.8
type GoAwayFrame struct { type GoAwayFrame struct {
FrameHeader FrameHeader
LastStreamID uint32 LastStreamID uint32
@ -934,7 +934,7 @@ func parseUnknownFrame(_ *frameCache, fh FrameHeader, countError func(string), p
} }
// A WindowUpdateFrame is used to implement flow control. // A WindowUpdateFrame is used to implement flow control.
// See http://http2.github.io/http2-spec/#rfc.section.6.9 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.9
type WindowUpdateFrame struct { type WindowUpdateFrame struct {
FrameHeader FrameHeader
Increment uint32 // never read with high bit set Increment uint32 // never read with high bit set
@ -1123,7 +1123,7 @@ func (f *Framer) WriteHeaders(p HeadersFrameParam) error {
} }
// A PriorityFrame specifies the sender-advised priority of a stream. // A PriorityFrame specifies the sender-advised priority of a stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.3 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.3
type PriorityFrame struct { type PriorityFrame struct {
FrameHeader FrameHeader
PriorityParam PriorityParam
@ -1193,7 +1193,7 @@ func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
} }
// A RSTStreamFrame allows for abnormal termination of a stream. // A RSTStreamFrame allows for abnormal termination of a stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.4 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.4
type RSTStreamFrame struct { type RSTStreamFrame struct {
FrameHeader FrameHeader
ErrCode ErrCode ErrCode ErrCode
@ -1225,7 +1225,7 @@ func (f *Framer) WriteRSTStream(streamID uint32, code ErrCode) error {
} }
// A ContinuationFrame is used to continue a sequence of header block fragments. // A ContinuationFrame is used to continue a sequence of header block fragments.
// See http://http2.github.io/http2-spec/#rfc.section.6.10 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.10
type ContinuationFrame struct { type ContinuationFrame struct {
FrameHeader FrameHeader
headerFragBuf []byte headerFragBuf []byte
@ -1266,7 +1266,7 @@ func (f *Framer) WriteContinuation(streamID uint32, endHeaders bool, headerBlock
} }
// A PushPromiseFrame is used to initiate a server stream. // A PushPromiseFrame is used to initiate a server stream.
// See http://http2.github.io/http2-spec/#rfc.section.6.6 // See https://httpwg.org/specs/rfc7540.html#rfc.section.6.6
type PushPromiseFrame struct { type PushPromiseFrame struct {
FrameHeader FrameHeader
PromiseID uint32 PromiseID uint32
@ -1532,7 +1532,8 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
fr.debugReadLoggerf("http2: decoded hpack field %+v", hf) fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
} }
if !httpguts.ValidHeaderFieldValue(hf.Value) { if !httpguts.ValidHeaderFieldValue(hf.Value) {
invalid = headerFieldValueError(hf.Value) // Don't include the value in the error, because it may be sensitive.
invalid = headerFieldValueError(hf.Name)
} }
isPseudo := strings.HasPrefix(hf.Name, ":") isPseudo := strings.HasPrefix(hf.Name, ":")
if isPseudo { if isPseudo {

17
vendor/golang.org/x/net/http2/go118.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.18
// +build go1.18
package http2
import (
"crypto/tls"
"net"
)
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
return tc.NetConn()
}

View file

@ -191,7 +191,7 @@ func appendTableSize(dst []byte, v uint32) []byte {
// bit prefix, to dst and returns the extended buffer. // bit prefix, to dst and returns the extended buffer.
// //
// See // See
// http://http2.github.io/http2-spec/compression.html#integer.representation // https://httpwg.org/specs/rfc7541.html#integer.representation
func appendVarInt(dst []byte, n byte, i uint64) []byte { func appendVarInt(dst []byte, n byte, i uint64) []byte {
k := uint64((1 << n) - 1) k := uint64((1 << n) - 1)
if i < k { if i < k {

View file

@ -59,7 +59,7 @@ func (hf HeaderField) String() string {
// Size returns the size of an entry per RFC 7541 section 4.1. // Size returns the size of an entry per RFC 7541 section 4.1.
func (hf HeaderField) Size() uint32 { func (hf HeaderField) Size() uint32 {
// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1 // https://httpwg.org/specs/rfc7541.html#rfc.section.4.1
// "The size of the dynamic table is the sum of the size of // "The size of the dynamic table is the sum of the size of
// its entries. The size of an entry is the sum of its name's // its entries. The size of an entry is the sum of its name's
// length in octets (as defined in Section 5.2), its value's // length in octets (as defined in Section 5.2), its value's
@ -158,7 +158,7 @@ func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
} }
type dynamicTable struct { type dynamicTable struct {
// http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2 // https://httpwg.org/specs/rfc7541.html#rfc.section.2.3.2
table headerFieldTable table headerFieldTable
size uint32 // in bytes size uint32 // in bytes
maxSize uint32 // current maxSize maxSize uint32 // current maxSize
@ -307,27 +307,27 @@ func (d *Decoder) parseHeaderFieldRepr() error {
case b&128 != 0: case b&128 != 0:
// Indexed representation. // Indexed representation.
// High bit set? // High bit set?
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.1 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.1
return d.parseFieldIndexed() return d.parseFieldIndexed()
case b&192 == 64: case b&192 == 64:
// 6.2.1 Literal Header Field with Incremental Indexing // 6.2.1 Literal Header Field with Incremental Indexing
// 0b10xxxxxx: top two bits are 10 // 0b10xxxxxx: top two bits are 10
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.1
return d.parseFieldLiteral(6, indexedTrue) return d.parseFieldLiteral(6, indexedTrue)
case b&240 == 0: case b&240 == 0:
// 6.2.2 Literal Header Field without Indexing // 6.2.2 Literal Header Field without Indexing
// 0b0000xxxx: top four bits are 0000 // 0b0000xxxx: top four bits are 0000
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.2
return d.parseFieldLiteral(4, indexedFalse) return d.parseFieldLiteral(4, indexedFalse)
case b&240 == 16: case b&240 == 16:
// 6.2.3 Literal Header Field never Indexed // 6.2.3 Literal Header Field never Indexed
// 0b0001xxxx: top four bits are 0001 // 0b0001xxxx: top four bits are 0001
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.3
return d.parseFieldLiteral(4, indexedNever) return d.parseFieldLiteral(4, indexedNever)
case b&224 == 32: case b&224 == 32:
// 6.3 Dynamic Table Size Update // 6.3 Dynamic Table Size Update
// Top three bits are '001'. // Top three bits are '001'.
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.3 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.3
return d.parseDynamicTableSizeUpdate() return d.parseDynamicTableSizeUpdate()
} }
@ -420,7 +420,7 @@ var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
// readVarInt reads an unsigned variable length integer off the // readVarInt reads an unsigned variable length integer off the
// beginning of p. n is the parameter as described in // beginning of p. n is the parameter as described in
// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1. // https://httpwg.org/specs/rfc7541.html#rfc.section.5.1.
// //
// n must always be between 1 and 8. // n must always be between 1 and 8.
// //

View file

@ -169,25 +169,50 @@ func buildRootHuffmanNode() {
// AppendHuffmanString appends s, as encoded in Huffman codes, to dst // AppendHuffmanString appends s, as encoded in Huffman codes, to dst
// and returns the extended buffer. // and returns the extended buffer.
func AppendHuffmanString(dst []byte, s string) []byte { func AppendHuffmanString(dst []byte, s string) []byte {
rembits := uint8(8) // This relies on the maximum huffman code length being 30 (See tables.go huffmanCodeLen array)
// So if a uint64 buffer has less than 32 valid bits can always accommodate another huffmanCode.
var (
x uint64 // buffer
n uint // number valid of bits present in x
)
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
if rembits == 8 { c := s[i]
dst = append(dst, 0) n += uint(huffmanCodeLen[c])
x <<= huffmanCodeLen[c] % 64
x |= uint64(huffmanCodes[c])
if n >= 32 {
n %= 32 // Normally would be -= 32 but %= 32 informs compiler 0 <= n <= 31 for upcoming shift
y := uint32(x >> n) // Compiler doesn't combine memory writes if y isn't uint32
dst = append(dst, byte(y>>24), byte(y>>16), byte(y>>8), byte(y))
} }
dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i])
} }
// Add padding bits if necessary
if rembits < 8 { if over := n % 8; over > 0 {
// special EOS symbol const (
code := uint32(0x3fffffff) eosCode = 0x3fffffff
nbits := uint8(30) eosNBits = 30
eosPadByte = eosCode >> (eosNBits - 8)
t := uint8(code >> (nbits - rembits)) )
dst[len(dst)-1] |= t pad := 8 - over
x = (x << pad) | (eosPadByte >> over)
n += pad // 8 now divides into n exactly
} }
// n in (0, 8, 16, 24, 32)
switch n / 8 {
case 0:
return dst return dst
case 1:
return append(dst, byte(x))
case 2:
y := uint16(x)
return append(dst, byte(y>>8), byte(y))
case 3:
y := uint16(x >> 8)
return append(dst, byte(y>>8), byte(y), byte(x))
}
// case 4:
y := uint32(x)
return append(dst, byte(y>>24), byte(y>>16), byte(y>>8), byte(y))
} }
// HuffmanEncodeLength returns the number of bytes required to encode // HuffmanEncodeLength returns the number of bytes required to encode
@ -199,35 +224,3 @@ func HuffmanEncodeLength(s string) uint64 {
} }
return (n + 7) / 8 return (n + 7) / 8
} }
// appendByteToHuffmanCode appends Huffman code for c to dst and
// returns the extended buffer and the remaining bits in the last
// element. The appending is not byte aligned and the remaining bits
// in the last element of dst is given in rembits.
func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) {
code := huffmanCodes[c]
nbits := huffmanCodeLen[c]
for {
if rembits > nbits {
t := uint8(code << (rembits - nbits))
dst[len(dst)-1] |= t
rembits -= nbits
break
}
t := uint8(code >> (nbits - rembits))
dst[len(dst)-1] |= t
nbits -= rembits
rembits = 8
if nbits == 0 {
break
}
dst = append(dst, 0)
}
return dst, rembits
}

View file

@ -13,7 +13,6 @@
// See https://http2.github.io/ for more information on HTTP/2. // See https://http2.github.io/ for more information on HTTP/2.
// //
// See https://http2.golang.org/ for a test server running this code. // See https://http2.golang.org/ for a test server running this code.
//
package http2 // import "golang.org/x/net/http2" package http2 // import "golang.org/x/net/http2"
import ( import (
@ -56,14 +55,14 @@ const (
ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
// SETTINGS_MAX_FRAME_SIZE default // SETTINGS_MAX_FRAME_SIZE default
// http://http2.github.io/http2-spec/#rfc.section.6.5.2 // https://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2
initialMaxFrameSize = 16384 initialMaxFrameSize = 16384
// NextProtoTLS is the NPN/ALPN protocol negotiated during // NextProtoTLS is the NPN/ALPN protocol negotiated during
// HTTP/2's TLS setup. // HTTP/2's TLS setup.
NextProtoTLS = "h2" NextProtoTLS = "h2"
// http://http2.github.io/http2-spec/#SettingValues // https://httpwg.org/specs/rfc7540.html#SettingValues
initialHeaderTableSize = 4096 initialHeaderTableSize = 4096
initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
@ -112,7 +111,7 @@ func (st streamState) String() string {
// Setting is a setting parameter: which setting it is, and its value. // Setting is a setting parameter: which setting it is, and its value.
type Setting struct { type Setting struct {
// ID is which setting is being set. // ID is which setting is being set.
// See http://http2.github.io/http2-spec/#SettingValues // See https://httpwg.org/specs/rfc7540.html#SettingFormat
ID SettingID ID SettingID
// Val is the value. // Val is the value.
@ -144,7 +143,7 @@ func (s Setting) Valid() error {
} }
// A SettingID is an HTTP/2 setting as defined in // A SettingID is an HTTP/2 setting as defined in
// http://http2.github.io/http2-spec/#iana-settings // https://httpwg.org/specs/rfc7540.html#iana-settings
type SettingID uint16 type SettingID uint16
const ( const (
@ -176,6 +175,7 @@ func (s SettingID) String() string {
// name (key). See httpguts.ValidHeaderName for the base rules. // name (key). See httpguts.ValidHeaderName for the base rules.
// //
// Further, http2 says: // Further, http2 says:
//
// "Just as in HTTP/1.x, header field names are strings of ASCII // "Just as in HTTP/1.x, header field names are strings of ASCII
// characters that are compared in a case-insensitive // characters that are compared in a case-insensitive
// fashion. However, header field names MUST be converted to // fashion. However, header field names MUST be converted to
@ -365,8 +365,8 @@ func (s *sorter) SortStrings(ss []string) {
// validPseudoPath reports whether v is a valid :path pseudo-header // validPseudoPath reports whether v is a valid :path pseudo-header
// value. It must be either: // value. It must be either:
// //
// *) a non-empty string starting with '/' // - a non-empty string starting with '/'
// *) the string '*', for OPTIONS requests. // - the string '*', for OPTIONS requests.
// //
// For now this is only used a quick check for deciding when to clean // For now this is only used a quick check for deciding when to clean
// up Opaque URLs before sending requests from the Transport. // up Opaque URLs before sending requests from the Transport.

17
vendor/golang.org/x/net/http2/not_go118.go generated vendored Normal file
View file

@ -0,0 +1,17 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.18
// +build !go1.18
package http2
import (
"crypto/tls"
"net"
)
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
return nil
}

View file

@ -143,7 +143,7 @@ type Server struct {
} }
func (s *Server) initialConnRecvWindowSize() int32 { func (s *Server) initialConnRecvWindowSize() int32 {
if s.MaxUploadBufferPerConnection > initialWindowSize { if s.MaxUploadBufferPerConnection >= initialWindowSize {
return s.MaxUploadBufferPerConnection return s.MaxUploadBufferPerConnection
} }
return 1 << 20 return 1 << 20
@ -315,6 +315,20 @@ type ServeConnOpts struct {
// requests. If nil, BaseConfig.Handler is used. If BaseConfig // requests. If nil, BaseConfig.Handler is used. If BaseConfig
// or BaseConfig.Handler is nil, http.DefaultServeMux is used. // or BaseConfig.Handler is nil, http.DefaultServeMux is used.
Handler http.Handler Handler http.Handler
// UpgradeRequest is an initial request received on a connection
// undergoing an h2c upgrade. The request body must have been
// completely read from the connection before calling ServeConn,
// and the 101 Switching Protocols response written.
UpgradeRequest *http.Request
// Settings is the decoded contents of the HTTP2-Settings header
// in an h2c upgrade request.
Settings []byte
// SawClientPreface is set if the HTTP/2 connection preface
// has already been read from the connection.
SawClientPreface bool
} }
func (o *ServeConnOpts) context() context.Context { func (o *ServeConnOpts) context() context.Context {
@ -383,6 +397,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
headerTableSize: initialHeaderTableSize, headerTableSize: initialHeaderTableSize,
serveG: newGoroutineLock(), serveG: newGoroutineLock(),
pushEnabled: true, pushEnabled: true,
sawClientPreface: opts.SawClientPreface,
} }
s.state.registerConn(sc) s.state.registerConn(sc)
@ -400,7 +415,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
if s.NewWriteScheduler != nil { if s.NewWriteScheduler != nil {
sc.writeSched = s.NewWriteScheduler() sc.writeSched = s.NewWriteScheduler()
} else { } else {
sc.writeSched = NewRandomWriteScheduler() sc.writeSched = NewPriorityWriteScheduler(nil)
} }
// These start at the RFC-specified defaults. If there is a higher // These start at the RFC-specified defaults. If there is a higher
@ -465,9 +480,27 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
} }
} }
if opts.Settings != nil {
fr := &SettingsFrame{
FrameHeader: FrameHeader{valid: true},
p: opts.Settings,
}
if err := fr.ForeachSetting(sc.processSetting); err != nil {
sc.rejectConn(ErrCodeProtocol, "invalid settings")
return
}
opts.Settings = nil
}
if hook := testHookGetServerConn; hook != nil { if hook := testHookGetServerConn; hook != nil {
hook(sc) hook(sc)
} }
if opts.UpgradeRequest != nil {
sc.upgradeRequest(opts.UpgradeRequest)
opts.UpgradeRequest = nil
}
sc.serve() sc.serve()
} }
@ -512,6 +545,7 @@ type serverConn struct {
// Everything following is owned by the serve loop; use serveG.check(): // Everything following is owned by the serve loop; use serveG.check():
serveG goroutineLock // used to verify funcs are on serve() serveG goroutineLock // used to verify funcs are on serve()
pushEnabled bool pushEnabled bool
sawClientPreface bool // preface has already been read, used in h2c upgrade
sawFirstSettings bool // got the initial SETTINGS frame after the preface sawFirstSettings bool // got the initial SETTINGS frame after the preface
needToSendSettingsAck bool needToSendSettingsAck bool
unackedSettings int // how many SETTINGS have we sent without ACKs? unackedSettings int // how many SETTINGS have we sent without ACKs?
@ -719,7 +753,15 @@ func (sc *serverConn) canonicalHeader(v string) string {
sc.canonHeader = make(map[string]string) sc.canonHeader = make(map[string]string)
} }
cv = http.CanonicalHeaderKey(v) cv = http.CanonicalHeaderKey(v)
// maxCachedCanonicalHeaders is an arbitrarily-chosen limit on the number of
// entries in the canonHeader cache. This should be larger than the number
// of unique, uncommon header keys likely to be sent by the peer, while not
// so high as to permit unreasonable memory usage if the peer sends an unbounded
// number of unique header keys.
const maxCachedCanonicalHeaders = 32
if len(sc.canonHeader) < maxCachedCanonicalHeaders {
sc.canonHeader[v] = cv sc.canonHeader[v] = cv
}
return cv return cv
} }
@ -827,9 +869,7 @@ func (sc *serverConn) serve() {
// Each connection starts with initialWindowSize inflow tokens. // Each connection starts with initialWindowSize inflow tokens.
// If a higher value is configured, we add more tokens. // If a higher value is configured, we add more tokens.
if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 { sc.sendWindowUpdate(nil)
sc.sendWindowUpdate(nil, int(diff))
}
if err := sc.readPreface(); err != nil { if err := sc.readPreface(); err != nil {
sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err) sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
@ -966,6 +1006,9 @@ var errPrefaceTimeout = errors.New("timeout waiting for client preface")
// returns errPrefaceTimeout on timeout, or an error if the greeting // returns errPrefaceTimeout on timeout, or an error if the greeting
// is invalid. // is invalid.
func (sc *serverConn) readPreface() error { func (sc *serverConn) readPreface() error {
if sc.sawClientPreface {
return nil
}
errc := make(chan error, 1) errc := make(chan error, 1)
go func() { go func() {
// Read the client preface // Read the client preface
@ -1326,6 +1369,9 @@ func (sc *serverConn) startGracefulShutdownInternal() {
func (sc *serverConn) goAway(code ErrCode) { func (sc *serverConn) goAway(code ErrCode) {
sc.serveG.check() sc.serveG.check()
if sc.inGoAway { if sc.inGoAway {
if sc.goAwayCode == ErrCodeNo {
sc.goAwayCode = code
}
return return
} }
sc.inGoAway = true sc.inGoAway = true
@ -1540,7 +1586,7 @@ func (sc *serverConn) closeStream(st *stream, err error) {
if p := st.body; p != nil { if p := st.body; p != nil {
// Return any buffered unread bytes worth of conn-level flow control. // Return any buffered unread bytes worth of conn-level flow control.
// See golang.org/issue/16481 // See golang.org/issue/16481
sc.sendWindowUpdate(nil, p.Len()) sc.sendWindowUpdate(nil)
p.CloseWithError(err) p.CloseWithError(err)
} }
@ -1688,7 +1734,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
// sendWindowUpdate, which also schedules sending the // sendWindowUpdate, which also schedules sending the
// frames. // frames.
sc.inflow.take(int32(f.Length)) sc.inflow.take(int32(f.Length))
sc.sendWindowUpdate(nil, int(f.Length)) // conn-level sc.sendWindowUpdate(nil) // conn-level
if st != nil && st.resetQueued { if st != nil && st.resetQueued {
// Already have a stream error in flight. Don't send another. // Already have a stream error in flight. Don't send another.
@ -1702,6 +1748,12 @@ func (sc *serverConn) processData(f *DataFrame) error {
// Sender sending more than they'd declared? // Sender sending more than they'd declared?
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes { if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
if sc.inflow.available() < int32(f.Length) {
return sc.countError("data_flow", streamError(id, ErrCodeFlowControl))
}
sc.inflow.take(int32(f.Length))
sc.sendWindowUpdate(nil) // conn-level
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes)) st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the // RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
// value of a content-length header field does not equal the sum of the // value of a content-length header field does not equal the sum of the
@ -1718,7 +1770,7 @@ func (sc *serverConn) processData(f *DataFrame) error {
if len(data) > 0 { if len(data) > 0 {
wrote, err := st.body.Write(data) wrote, err := st.body.Write(data)
if err != nil { if err != nil {
sc.sendWindowUpdate(nil, int(f.Length)-wrote) sc.sendWindowUpdate32(nil, int32(f.Length)-int32(wrote))
return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed)) return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed))
} }
if wrote != len(data) { if wrote != len(data) {
@ -1907,6 +1959,26 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
return nil return nil
} }
func (sc *serverConn) upgradeRequest(req *http.Request) {
sc.serveG.check()
id := uint32(1)
sc.maxClientStreamID = id
st := sc.newStream(id, 0, stateHalfClosedRemote)
st.reqTrailer = req.Trailer
if st.reqTrailer != nil {
st.trailer = make(http.Header)
}
rw := sc.newResponseWriter(st, req)
// Disable any read deadline set by the net/http package
// prior to the upgrade.
if sc.hs.ReadTimeout != 0 {
sc.conn.SetReadDeadline(time.Time{})
}
go sc.runHandler(rw, req, sc.handler.ServeHTTP)
}
func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error { func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
sc := st.sc sc := st.sc
sc.serveG.check() sc.serveG.check()
@ -2025,12 +2097,6 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol)) return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol))
} }
bodyOpen := !f.StreamEnded()
if rp.method == "HEAD" && bodyOpen {
// HEAD requests can't have bodies
return nil, nil, sc.countError("head_body", streamError(f.StreamID, ErrCodeProtocol))
}
rp.header = make(http.Header) rp.header = make(http.Header)
for _, hf := range f.RegularFields() { for _, hf := range f.RegularFields() {
rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value) rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
@ -2043,6 +2109,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
bodyOpen := !f.StreamEnded()
if bodyOpen { if bodyOpen {
if vv, ok := rp.header["Content-Length"]; ok { if vv, ok := rp.header["Content-Length"]; ok {
if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil { if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
@ -2137,6 +2204,11 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
} }
req = req.WithContext(st.ctx) req = req.WithContext(st.ctx)
rw := sc.newResponseWriter(st, req)
return rw, req, nil
}
func (sc *serverConn) newResponseWriter(st *stream, req *http.Request) *responseWriter {
rws := responseWriterStatePool.Get().(*responseWriterState) rws := responseWriterStatePool.Get().(*responseWriterState)
bwSave := rws.bw bwSave := rws.bw
*rws = responseWriterState{} // zero all the fields *rws = responseWriterState{} // zero all the fields
@ -2145,10 +2217,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
rws.bw.Reset(chunkWriter{rws}) rws.bw.Reset(chunkWriter{rws})
rws.stream = st rws.stream = st
rws.req = req rws.req = req
rws.body = body return &responseWriter{rws: rws}
rw := &responseWriter{rws: rws}
return rw, req, nil
} }
// Run on its own goroutine. // Run on its own goroutine.
@ -2156,6 +2225,9 @@ func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler
didPanic := true didPanic := true
defer func() { defer func() {
rw.rws.stream.cancelCtx() rw.rws.stream.cancelCtx()
if req.MultipartForm != nil {
req.MultipartForm.RemoveAll()
}
if didPanic { if didPanic {
e := recover() e := recover()
sc.writeFrameFromHandler(FrameWriteRequest{ sc.writeFrameFromHandler(FrameWriteRequest{
@ -2250,17 +2322,32 @@ func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) {
func (sc *serverConn) noteBodyRead(st *stream, n int) { func (sc *serverConn) noteBodyRead(st *stream, n int) {
sc.serveG.check() sc.serveG.check()
sc.sendWindowUpdate(nil, n) // conn-level sc.sendWindowUpdate(nil) // conn-level
if st.state != stateHalfClosedRemote && st.state != stateClosed { if st.state != stateHalfClosedRemote && st.state != stateClosed {
// Don't send this WINDOW_UPDATE if the stream is closed // Don't send this WINDOW_UPDATE if the stream is closed
// remotely. // remotely.
sc.sendWindowUpdate(st, n) sc.sendWindowUpdate(st)
} }
} }
// st may be nil for conn-level // st may be nil for conn-level
func (sc *serverConn) sendWindowUpdate(st *stream, n int) { func (sc *serverConn) sendWindowUpdate(st *stream) {
sc.serveG.check() sc.serveG.check()
var n int32
if st == nil {
if avail, windowSize := sc.inflow.available(), sc.srv.initialConnRecvWindowSize(); avail > windowSize/2 {
return
} else {
n = windowSize - avail
}
} else {
if avail, windowSize := st.inflow.available(), sc.srv.initialStreamRecvWindowSize(); avail > windowSize/2 {
return
} else {
n = windowSize - avail
}
}
// "The legal range for the increment to the flow control // "The legal range for the increment to the flow control
// window is 1 to 2^31-1 (2,147,483,647) octets." // window is 1 to 2^31-1 (2,147,483,647) octets."
// A Go Read call on 64-bit machines could in theory read // A Go Read call on 64-bit machines could in theory read
@ -2308,17 +2395,18 @@ type requestBody struct {
_ incomparable _ incomparable
stream *stream stream *stream
conn *serverConn conn *serverConn
closed bool // for use by Close only closeOnce sync.Once // for use by Close only
sawEOF bool // for use by Read only sawEOF bool // for use by Read only
pipe *pipe // non-nil if we have a HTTP entity message body pipe *pipe // non-nil if we have a HTTP entity message body
needsContinue bool // need to send a 100-continue needsContinue bool // need to send a 100-continue
} }
func (b *requestBody) Close() error { func (b *requestBody) Close() error {
if b.pipe != nil && !b.closed { b.closeOnce.Do(func() {
if b.pipe != nil {
b.pipe.BreakWithError(errClosedBody) b.pipe.BreakWithError(errClosedBody)
} }
b.closed = true })
return nil return nil
} }
@ -2362,7 +2450,6 @@ type responseWriterState struct {
// immutable within a request: // immutable within a request:
stream *stream stream *stream
req *http.Request req *http.Request
body *requestBody // to close at end of request, if DATA frames didn't
conn *serverConn conn *serverConn
// TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc // TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc
@ -2426,6 +2513,10 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
rws.writeHeader(200) rws.writeHeader(200)
} }
if rws.handlerDone {
rws.promoteUndeclaredTrailers()
}
isHeadResp := rws.req.Method == "HEAD" isHeadResp := rws.req.Method == "HEAD"
if !rws.sentHeader { if !rws.sentHeader {
rws.sentHeader = true rws.sentHeader = true
@ -2497,10 +2588,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
return 0, nil return 0, nil
} }
if rws.handlerDone {
rws.promoteUndeclaredTrailers()
}
// only send trailers if they have actually been defined by the // only send trailers if they have actually been defined by the
// server handler. // server handler.
hasNonemptyTrailers := rws.hasNonemptyTrailers() hasNonemptyTrailers := rws.hasNonemptyTrailers()
@ -2538,6 +2625,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
// prior to the headers being written. If the set of trailers is fixed // prior to the headers being written. If the set of trailers is fixed
// or known before the header is written, the normal Go trailers mechanism // or known before the header is written, the normal Go trailers mechanism
// is preferred: // is preferred:
//
// https://golang.org/pkg/net/http/#ResponseWriter // https://golang.org/pkg/net/http/#ResponseWriter
// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers // https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
const TrailerPrefix = "Trailer:" const TrailerPrefix = "Trailer:"
@ -2635,8 +2723,7 @@ func checkWriteHeaderCode(code int) {
// Issue 22880: require valid WriteHeader status codes. // Issue 22880: require valid WriteHeader status codes.
// For now we only enforce that it's three digits. // For now we only enforce that it's three digits.
// In the future we might block things over 599 (600 and above aren't defined // In the future we might block things over 599 (600 and above aren't defined
// at http://httpwg.org/specs/rfc7231.html#status.codes) // at http://httpwg.org/specs/rfc7231.html#status.codes).
// and we might block under 200 (once we have more mature 1xx support).
// But for now any three digits. // But for now any three digits.
// //
// We used to send "HTTP/1.1 000 0" on the wire in responses but there's // We used to send "HTTP/1.1 000 0" on the wire in responses but there's
@ -2657,15 +2744,43 @@ func (w *responseWriter) WriteHeader(code int) {
} }
func (rws *responseWriterState) writeHeader(code int) { func (rws *responseWriterState) writeHeader(code int) {
if !rws.wroteHeader { if rws.wroteHeader {
return
}
checkWriteHeaderCode(code) checkWriteHeaderCode(code)
// Handle informational headers
if code >= 100 && code <= 199 {
// Per RFC 8297 we must not clear the current header map
h := rws.handlerHeader
_, cl := h["Content-Length"]
_, te := h["Transfer-Encoding"]
if cl || te {
h = h.Clone()
h.Del("Content-Length")
h.Del("Transfer-Encoding")
}
if rws.conn.writeHeaders(rws.stream, &writeResHeaders{
streamID: rws.stream.id,
httpResCode: code,
h: h,
endStream: rws.handlerDone && !rws.hasTrailers(),
}) != nil {
rws.dirty = true
}
return
}
rws.wroteHeader = true rws.wroteHeader = true
rws.status = code rws.status = code
if len(rws.handlerHeader) > 0 { if len(rws.handlerHeader) > 0 {
rws.snapHeader = cloneHeader(rws.handlerHeader) rws.snapHeader = cloneHeader(rws.handlerHeader)
} }
} }
}
func cloneHeader(h http.Header) http.Header { func cloneHeader(h http.Header) http.Header {
h2 := make(http.Header, len(h)) h2 := make(http.Header, len(h))

View file

@ -16,7 +16,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"log" "log"
"math" "math"
mathrand "math/rand" mathrand "math/rand"
@ -68,13 +67,23 @@ const (
// A Transport internally caches connections to servers. It is safe // A Transport internally caches connections to servers. It is safe
// for concurrent use by multiple goroutines. // for concurrent use by multiple goroutines.
type Transport struct { type Transport struct {
// DialTLS specifies an optional dial function for creating // DialTLSContext specifies an optional dial function with context for
// TLS connections for requests. // creating TLS connections for requests.
// //
// If DialTLS is nil, tls.Dial is used. // If DialTLSContext and DialTLS is nil, tls.Dial is used.
// //
// If the returned net.Conn has a ConnectionState method like tls.Conn, // If the returned net.Conn has a ConnectionState method like tls.Conn,
// it will be used to set http.Response.TLS. // it will be used to set http.Response.TLS.
DialTLSContext func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error)
// DialTLS specifies an optional dial function for creating
// TLS connections for requests.
//
// If DialTLSContext and DialTLS is nil, tls.Dial is used.
//
// Deprecated: Use DialTLSContext instead, which allows the transport
// to cancel dials as soon as they are no longer needed.
// If both are set, DialTLSContext takes priority.
DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error) DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error)
// TLSClientConfig specifies the TLS configuration to use with // TLSClientConfig specifies the TLS configuration to use with
@ -250,6 +259,7 @@ func (t *Transport) initConnPool() {
type ClientConn struct { type ClientConn struct {
t *Transport t *Transport
tconn net.Conn // usually *tls.Conn, except specialized impls tconn net.Conn // usually *tls.Conn, except specialized impls
tconnClosed bool
tlsState *tls.ConnectionState // nil only for specialized impls tlsState *tls.ConnectionState // nil only for specialized impls
reused uint32 // whether conn is being reused; atomic reused uint32 // whether conn is being reused; atomic
singleUse bool // whether being used for a single http.Request singleUse bool // whether being used for a single http.Request
@ -336,7 +346,7 @@ type clientStream struct {
reqBody io.ReadCloser reqBody io.ReadCloser
reqBodyContentLength int64 // -1 means unknown reqBodyContentLength int64 // -1 means unknown
reqBodyClosed bool // body has been closed; guarded by cc.mu reqBodyClosed chan struct{} // guarded by cc.mu; non-nil on Close, closed when done
// owned by writeRequest: // owned by writeRequest:
sentEndStream bool // sent an END_STREAM flag to the peer sentEndStream bool // sent an END_STREAM flag to the peer
@ -376,9 +386,8 @@ func (cs *clientStream) abortStreamLocked(err error) {
cs.abortErr = err cs.abortErr = err
close(cs.abort) close(cs.abort)
}) })
if cs.reqBody != nil && !cs.reqBodyClosed { if cs.reqBody != nil {
cs.reqBody.Close() cs.closeReqBodyLocked()
cs.reqBodyClosed = true
} }
// TODO(dneil): Clean up tests where cs.cc.cond is nil. // TODO(dneil): Clean up tests where cs.cc.cond is nil.
if cs.cc.cond != nil { if cs.cc.cond != nil {
@ -391,13 +400,24 @@ func (cs *clientStream) abortRequestBodyWrite() {
cc := cs.cc cc := cs.cc
cc.mu.Lock() cc.mu.Lock()
defer cc.mu.Unlock() defer cc.mu.Unlock()
if cs.reqBody != nil && !cs.reqBodyClosed { if cs.reqBody != nil && cs.reqBodyClosed == nil {
cs.reqBody.Close() cs.closeReqBodyLocked()
cs.reqBodyClosed = true
cc.cond.Broadcast() cc.cond.Broadcast()
} }
} }
func (cs *clientStream) closeReqBodyLocked() {
if cs.reqBodyClosed != nil {
return
}
cs.reqBodyClosed = make(chan struct{})
reqBodyClosed := cs.reqBodyClosed
go func() {
cs.reqBody.Close()
close(reqBodyClosed)
}()
}
type stickyErrWriter struct { type stickyErrWriter struct {
conn net.Conn conn net.Conn
timeout time.Duration timeout time.Duration
@ -501,12 +521,14 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
if req, err = shouldRetryRequest(req, err); err == nil { if req, err = shouldRetryRequest(req, err); err == nil {
// After the first retry, do exponential backoff with 10% jitter. // After the first retry, do exponential backoff with 10% jitter.
if retry == 0 { if retry == 0 {
t.vlogf("RoundTrip retrying after failure: %v", err)
continue continue
} }
backoff := float64(uint(1) << (uint(retry) - 1)) backoff := float64(uint(1) << (uint(retry) - 1))
backoff += backoff * (0.1 * mathrand.Float64()) backoff += backoff * (0.1 * mathrand.Float64())
select { select {
case <-time.After(time.Second * time.Duration(backoff)): case <-time.After(time.Second * time.Duration(backoff)):
t.vlogf("RoundTrip retrying after failure: %v", err)
continue continue
case <-req.Context().Done(): case <-req.Context().Done():
err = req.Context().Err() err = req.Context().Err()
@ -591,7 +613,7 @@ func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse b
if err != nil { if err != nil {
return nil, err return nil, err
} }
tconn, err := t.dialTLS(ctx)("tcp", addr, t.newTLSConfig(host)) tconn, err := t.dialTLS(ctx, "tcp", addr, t.newTLSConfig(host))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -612,12 +634,14 @@ func (t *Transport) newTLSConfig(host string) *tls.Config {
return cfg return cfg
} }
func (t *Transport) dialTLS(ctx context.Context) func(string, string, *tls.Config) (net.Conn, error) { func (t *Transport) dialTLS(ctx context.Context, network, addr string, tlsCfg *tls.Config) (net.Conn, error) {
if t.DialTLS != nil { if t.DialTLSContext != nil {
return t.DialTLS return t.DialTLSContext(ctx, network, addr, tlsCfg)
} else if t.DialTLS != nil {
return t.DialTLS(network, addr, tlsCfg)
} }
return func(network, addr string, cfg *tls.Config) (net.Conn, error) {
tlsCn, err := t.dialTLSWithContext(ctx, network, addr, cfg) tlsCn, err := t.dialTLSWithContext(ctx, network, addr, tlsCfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -630,7 +654,6 @@ func (t *Transport) dialTLS(ctx context.Context) func(string, string, *tls.Confi
} }
return tlsCn, nil return tlsCn, nil
} }
}
// disableKeepAlives reports whether connections should be closed as // disableKeepAlives reports whether connections should be closed as
// soon as possible after handling the first request. // soon as possible after handling the first request.
@ -732,11 +755,13 @@ func (cc *ClientConn) healthCheck() {
// trigger the healthCheck again if there is no frame received. // trigger the healthCheck again if there is no frame received.
ctx, cancel := context.WithTimeout(context.Background(), pingTimeout) ctx, cancel := context.WithTimeout(context.Background(), pingTimeout)
defer cancel() defer cancel()
cc.vlogf("http2: Transport sending health check")
err := cc.Ping(ctx) err := cc.Ping(ctx)
if err != nil { if err != nil {
cc.vlogf("http2: Transport health check failure: %v", err)
cc.closeForLostPing() cc.closeForLostPing()
cc.t.connPool().MarkDead(cc) } else {
return cc.vlogf("http2: Transport health check success")
} }
} }
@ -907,6 +932,24 @@ func (cc *ClientConn) onIdleTimeout() {
cc.closeIfIdle() cc.closeIfIdle()
} }
func (cc *ClientConn) closeConn() {
t := time.AfterFunc(250*time.Millisecond, cc.forceCloseConn)
defer t.Stop()
cc.tconn.Close()
}
// A tls.Conn.Close can hang for a long time if the peer is unresponsive.
// Try to shut it down more aggressively.
func (cc *ClientConn) forceCloseConn() {
tc, ok := cc.tconn.(*tls.Conn)
if !ok {
return
}
if nc := tlsUnderlyingConn(tc); nc != nil {
nc.Close()
}
}
func (cc *ClientConn) closeIfIdle() { func (cc *ClientConn) closeIfIdle() {
cc.mu.Lock() cc.mu.Lock()
if len(cc.streams) > 0 || cc.streamsReserved > 0 { if len(cc.streams) > 0 || cc.streamsReserved > 0 {
@ -921,7 +964,7 @@ func (cc *ClientConn) closeIfIdle() {
if VerboseLogs { if VerboseLogs {
cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2) cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2)
} }
cc.tconn.Close() cc.closeConn()
} }
func (cc *ClientConn) isDoNotReuseAndIdle() bool { func (cc *ClientConn) isDoNotReuseAndIdle() bool {
@ -938,7 +981,7 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
return err return err
} }
// Wait for all in-flight streams to complete or connection to close // Wait for all in-flight streams to complete or connection to close
done := make(chan error, 1) done := make(chan struct{})
cancelled := false // guarded by cc.mu cancelled := false // guarded by cc.mu
go func() { go func() {
cc.mu.Lock() cc.mu.Lock()
@ -946,7 +989,7 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
for { for {
if len(cc.streams) == 0 || cc.closed { if len(cc.streams) == 0 || cc.closed {
cc.closed = true cc.closed = true
done <- cc.tconn.Close() close(done)
break break
} }
if cancelled { if cancelled {
@ -957,8 +1000,9 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error {
}() }()
shutdownEnterWaitStateHook() shutdownEnterWaitStateHook()
select { select {
case err := <-done: case <-done:
return err cc.closeConn()
return nil
case <-ctx.Done(): case <-ctx.Done():
cc.mu.Lock() cc.mu.Lock()
// Free the goroutine above // Free the goroutine above
@ -995,15 +1039,15 @@ func (cc *ClientConn) sendGoAway() error {
// closes the client connection immediately. In-flight requests are interrupted. // closes the client connection immediately. In-flight requests are interrupted.
// err is sent to streams. // err is sent to streams.
func (cc *ClientConn) closeForError(err error) error { func (cc *ClientConn) closeForError(err error) {
cc.mu.Lock() cc.mu.Lock()
cc.closed = true cc.closed = true
for _, cs := range cc.streams { for _, cs := range cc.streams {
cs.abortStreamLocked(err) cs.abortStreamLocked(err)
} }
defer cc.cond.Broadcast() cc.cond.Broadcast()
defer cc.mu.Unlock() cc.mu.Unlock()
return cc.tconn.Close() cc.closeConn()
} }
// Close closes the client connection immediately. // Close closes the client connection immediately.
@ -1011,16 +1055,17 @@ func (cc *ClientConn) closeForError(err error) error {
// In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead. // In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead.
func (cc *ClientConn) Close() error { func (cc *ClientConn) Close() error {
err := errors.New("http2: client connection force closed via ClientConn.Close") err := errors.New("http2: client connection force closed via ClientConn.Close")
return cc.closeForError(err) cc.closeForError(err)
return nil
} }
// closes the client connection immediately. In-flight requests are interrupted. // closes the client connection immediately. In-flight requests are interrupted.
func (cc *ClientConn) closeForLostPing() error { func (cc *ClientConn) closeForLostPing() {
err := errors.New("http2: client connection lost") err := errors.New("http2: client connection lost")
if f := cc.t.CountError; f != nil { if f := cc.t.CountError; f != nil {
f("conn_close_lost_ping") f("conn_close_lost_ping")
} }
return cc.closeForError(err) cc.closeForError(err)
} }
// errRequestCanceled is a copy of net/http's errRequestCanceled because it's not // errRequestCanceled is a copy of net/http's errRequestCanceled because it's not
@ -1252,13 +1297,13 @@ func (cs *clientStream) writeRequest(req *http.Request) (err error) {
} }
continueTimeout := cc.t.expectContinueTimeout() continueTimeout := cc.t.expectContinueTimeout()
if continueTimeout != 0 && if continueTimeout != 0 {
!httpguts.HeaderValuesContainsToken( if !httpguts.HeaderValuesContainsToken(req.Header["Expect"], "100-continue") {
req.Header["Expect"],
"100-continue") {
continueTimeout = 0 continueTimeout = 0
} else {
cs.on100 = make(chan struct{}, 1) cs.on100 = make(chan struct{}, 1)
} }
}
// Past this point (where we send request headers), it is possible for // Past this point (where we send request headers), it is possible for
// RoundTrip to return successfully. Since the RoundTrip contract permits // RoundTrip to return successfully. Since the RoundTrip contract permits
@ -1398,11 +1443,19 @@ func (cs *clientStream) cleanupWriteRequest(err error) {
// and in multiple cases: server replies <=299 and >299 // and in multiple cases: server replies <=299 and >299
// while still writing request body // while still writing request body
cc.mu.Lock() cc.mu.Lock()
mustCloseBody := false
if cs.reqBody != nil && cs.reqBodyClosed == nil {
mustCloseBody = true
cs.reqBodyClosed = make(chan struct{})
}
bodyClosed := cs.reqBodyClosed bodyClosed := cs.reqBodyClosed
cs.reqBodyClosed = true
cc.mu.Unlock() cc.mu.Unlock()
if !bodyClosed && cs.reqBody != nil { if mustCloseBody {
cs.reqBody.Close() cs.reqBody.Close()
close(bodyClosed)
}
if bodyClosed != nil {
<-bodyClosed
} }
if err != nil && cs.sentEndStream { if err != nil && cs.sentEndStream {
@ -1582,7 +1635,7 @@ func (cs *clientStream) writeRequestBody(req *http.Request) (err error) {
} }
if err != nil { if err != nil {
cc.mu.Lock() cc.mu.Lock()
bodyClosed := cs.reqBodyClosed bodyClosed := cs.reqBodyClosed != nil
cc.mu.Unlock() cc.mu.Unlock()
switch { switch {
case bodyClosed: case bodyClosed:
@ -1677,7 +1730,7 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error)
if cc.closed { if cc.closed {
return 0, errClientConnClosed return 0, errClientConnClosed
} }
if cs.reqBodyClosed { if cs.reqBodyClosed != nil {
return 0, errStopReqBodyWrite return 0, errStopReqBodyWrite
} }
select { select {
@ -1748,7 +1801,8 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
} }
for _, v := range vv { for _, v := range vv {
if !httpguts.ValidHeaderFieldValue(v) { if !httpguts.ValidHeaderFieldValue(v) {
return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k) // Don't include the value in the error, because it may be sensitive.
return nil, fmt.Errorf("invalid HTTP header value for header %q", k)
} }
} }
} }
@ -1972,13 +2026,13 @@ func (cc *ClientConn) forgetStreamID(id uint32) {
// wake up RoundTrip if there is a pending request. // wake up RoundTrip if there is a pending request.
cc.cond.Broadcast() cc.cond.Broadcast()
closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil
if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 { if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 {
if VerboseLogs { if VerboseLogs {
cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, cc.nextStreamID-2) cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, cc.nextStreamID-2)
} }
cc.closed = true cc.closed = true
defer cc.tconn.Close() defer cc.closeConn()
} }
cc.mu.Unlock() cc.mu.Unlock()
@ -2025,8 +2079,8 @@ func isEOFOrNetReadError(err error) bool {
func (rl *clientConnReadLoop) cleanup() { func (rl *clientConnReadLoop) cleanup() {
cc := rl.cc cc := rl.cc
defer cc.tconn.Close() cc.t.connPool().MarkDead(cc)
defer cc.t.connPool().MarkDead(cc) defer cc.closeConn()
defer close(cc.readerDone) defer close(cc.readerDone)
if cc.idleTimer != nil { if cc.idleTimer != nil {
@ -2048,6 +2102,7 @@ func (rl *clientConnReadLoop) cleanup() {
err = io.ErrUnexpectedEOF err = io.ErrUnexpectedEOF
} }
cc.closed = true cc.closed = true
for _, cs := range cc.streams { for _, cs := range cc.streams {
select { select {
case <-cs.peerClosed: case <-cs.peerClosed:
@ -2641,7 +2696,6 @@ func (rl *clientConnReadLoop) processGoAway(f *GoAwayFrame) error {
if fn := cc.t.CountError; fn != nil { if fn := cc.t.CountError; fn != nil {
fn("recv_goaway_" + f.ErrCode.stringToken()) fn("recv_goaway_" + f.ErrCode.stringToken())
} }
} }
cc.setGoAway(f) cc.setGoAway(f)
return nil return nil
@ -2881,7 +2935,12 @@ func (t *Transport) logf(format string, args ...interface{}) {
log.Printf(format, args...) log.Printf(format, args...)
} }
var noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil)) var noBody io.ReadCloser = noBodyReader{}
type noBodyReader struct{}
func (noBodyReader) Close() error { return nil }
func (noBodyReader) Read([]byte) (int, error) { return 0, io.EOF }
type missingBody struct{} type missingBody struct{}
@ -2990,7 +3049,7 @@ func traceGotConn(req *http.Request, cc *ClientConn, reused bool) {
cc.mu.Lock() cc.mu.Lock()
ci.WasIdle = len(cc.streams) == 0 && reused ci.WasIdle = len(cc.streams) == 0 && reused
if ci.WasIdle && !cc.lastActive.IsZero() { if ci.WasIdle && !cc.lastActive.IsZero() {
ci.IdleTime = time.Now().Sub(cc.lastActive) ci.IdleTime = time.Since(cc.lastActive)
} }
cc.mu.Unlock() cc.mu.Unlock()

View file

@ -32,7 +32,8 @@ type WriteScheduler interface {
// Pop dequeues the next frame to write. Returns false if no frames can // Pop dequeues the next frame to write. Returns false if no frames can
// be written. Frames with a given wr.StreamID() are Pop'd in the same // be written. Frames with a given wr.StreamID() are Pop'd in the same
// order they are Push'd. No frames should be discarded except by CloseStream. // order they are Push'd, except RST_STREAM frames. No frames should be
// discarded except by CloseStream.
Pop() (wr FrameWriteRequest, ok bool) Pop() (wr FrameWriteRequest, ok bool)
} }
@ -52,6 +53,7 @@ type FrameWriteRequest struct {
// stream is the stream on which this frame will be written. // stream is the stream on which this frame will be written.
// nil for non-stream frames like PING and SETTINGS. // nil for non-stream frames like PING and SETTINGS.
// nil for RST_STREAM streams, which use the StreamError.StreamID field instead.
stream *stream stream *stream
// done, if non-nil, must be a buffered channel with space for // done, if non-nil, must be a buffered channel with space for

View file

@ -383,16 +383,15 @@ func (ws *priorityWriteScheduler) AdjustStream(streamID uint32, priority Priorit
func (ws *priorityWriteScheduler) Push(wr FrameWriteRequest) { func (ws *priorityWriteScheduler) Push(wr FrameWriteRequest) {
var n *priorityNode var n *priorityNode
if id := wr.StreamID(); id == 0 { if wr.isControl() {
n = &ws.root n = &ws.root
} else { } else {
id := wr.StreamID()
n = ws.nodes[id] n = ws.nodes[id]
if n == nil { if n == nil {
// id is an idle or closed stream. wr should not be a HEADERS or // id is an idle or closed stream. wr should not be a HEADERS or
// DATA frame. However, wr can be a RST_STREAM. In this case, we // DATA frame. In other case, we push wr onto the root, rather
// push wr onto the root, rather than creating a new priorityNode, // than creating a new priorityNode.
// since RST_STREAM is tiny and the stream's priority is unknown
// anyway. See issue #17919.
if wr.DataSize() > 0 { if wr.DataSize() > 0 {
panic("add DATA on non-open stream") panic("add DATA on non-open stream")
} }

View file

@ -45,11 +45,11 @@ func (ws *randomWriteScheduler) AdjustStream(streamID uint32, priority PriorityP
} }
func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) { func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) {
id := wr.StreamID() if wr.isControl() {
if id == 0 {
ws.zero.push(wr) ws.zero.push(wr)
return return
} }
id := wr.StreamID()
q, ok := ws.sq[id] q, ok := ws.sq[id]
if !ok { if !ok {
q = ws.queuePool.get() q = ws.queuePool.get()
@ -59,7 +59,7 @@ func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) {
} }
func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) { func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) {
// Control frames first. // Control and RST_STREAM frames first.
if !ws.zero.empty() { if !ws.zero.empty() {
return ws.zero.shift(), true return ws.zero.shift(), true
} }

View file

@ -395,7 +395,7 @@ func New(family, title string) Trace {
} }
func (tr *trace) Finish() { func (tr *trace) Finish() {
elapsed := time.Now().Sub(tr.Start) elapsed := time.Since(tr.Start)
tr.mu.Lock() tr.mu.Lock()
tr.Elapsed = elapsed tr.Elapsed = elapsed
tr.mu.Unlock() tr.mu.Unlock()

3
vendor/golang.org/x/sync/AUTHORS generated vendored
View file

@ -1,3 +0,0 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

View file

@ -1,3 +0,0 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

View file

@ -8,22 +8,35 @@ package errgroup
import ( import (
"context" "context"
"fmt"
"sync" "sync"
) )
type token struct{}
// A Group is a collection of goroutines working on subtasks that are part of // A Group is a collection of goroutines working on subtasks that are part of
// the same overall task. // the same overall task.
// //
// A zero Group is valid and does not cancel on error. // A zero Group is valid, has no limit on the number of active goroutines,
// and does not cancel on error.
type Group struct { type Group struct {
cancel func() cancel func()
wg sync.WaitGroup wg sync.WaitGroup
sem chan token
errOnce sync.Once errOnce sync.Once
err error err error
} }
func (g *Group) done() {
if g.sem != nil {
<-g.sem
}
g.wg.Done()
}
// WithContext returns a new Group and an associated Context derived from ctx. // WithContext returns a new Group and an associated Context derived from ctx.
// //
// The derived Context is canceled the first time a function passed to Go // The derived Context is canceled the first time a function passed to Go
@ -45,14 +58,19 @@ func (g *Group) Wait() error {
} }
// Go calls the given function in a new goroutine. // Go calls the given function in a new goroutine.
// It blocks until the new goroutine can be added without the number of
// active goroutines in the group exceeding the configured limit.
// //
// The first call to return a non-nil error cancels the group; its error will be // The first call to return a non-nil error cancels the group; its error will be
// returned by Wait. // returned by Wait.
func (g *Group) Go(f func() error) { func (g *Group) Go(f func() error) {
g.wg.Add(1) if g.sem != nil {
g.sem <- token{}
}
g.wg.Add(1)
go func() { go func() {
defer g.wg.Done() defer g.done()
if err := f(); err != nil { if err := f(); err != nil {
g.errOnce.Do(func() { g.errOnce.Do(func() {
@ -64,3 +82,51 @@ func (g *Group) Go(f func() error) {
} }
}() }()
} }
// TryGo calls the given function in a new goroutine only if the number of
// active goroutines in the group is currently below the configured limit.
//
// The return value reports whether the goroutine was started.
func (g *Group) TryGo(f func() error) bool {
if g.sem != nil {
select {
case g.sem <- token{}:
// Note: this allows barging iff channels in general allow barging.
default:
return false
}
}
g.wg.Add(1)
go func() {
defer g.done()
if err := f(); err != nil {
g.errOnce.Do(func() {
g.err = err
if g.cancel != nil {
g.cancel()
}
})
}
}()
return true
}
// SetLimit limits the number of active goroutines in this group to at most n.
// A negative value indicates no limit.
//
// Any subsequent call to the Go method will block until it can add an active
// goroutine without exceeding the configured limit.
//
// The limit must not be modified while any goroutines in the group are active.
func (g *Group) SetLimit(n int) {
if n < 0 {
g.sem = nil
return
}
if len(g.sem) != 0 {
panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem)))
}
g.sem = make(chan token, n)
}

View file

@ -6,7 +6,10 @@ package cpu
import "runtime" import "runtime"
const cacheLineSize = 64 // cacheLineSize is used to prevent false sharing of cache lines.
// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size.
// It doesn't cost much and is much more future-proof.
const cacheLineSize = 128
func initOptions() { func initOptions() {
options = []option{ options = []option{

15
vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go generated vendored Normal file
View file

@ -0,0 +1,15 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !aix && !linux && (ppc64 || ppc64le)
// +build !aix
// +build !linux
// +build ppc64 ppc64le
package cpu
func archInit() {
PPC64.IsPOWER8 = true
Initialized = true
}

31
vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s generated vendored Normal file
View file

@ -0,0 +1,31 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h"
//
// System call support for ppc64, BSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

View file

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package unix package unix

View file

@ -4,9 +4,7 @@
package unix package unix
import ( import "unsafe"
"unsafe"
)
// IoctlRetInt performs an ioctl operation specified by req on a device // IoctlRetInt performs an ioctl operation specified by req on a device
// associated with opened file descriptor fd, and returns a non-negative // associated with opened file descriptor fd, and returns a non-negative
@ -217,3 +215,19 @@ func IoctlKCMAttach(fd int, info KCMAttach) error {
func IoctlKCMUnattach(fd int, info KCMUnattach) error { func IoctlKCMUnattach(fd int, info KCMUnattach) error {
return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info)) return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
} }
// IoctlLoopGetStatus64 gets the status of the loop device associated with the
// file descriptor fd using the LOOP_GET_STATUS64 operation.
func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
var value LoopInfo64
if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
return nil, err
}
return &value, nil
}
// IoctlLoopSetStatus64 sets the status of the loop device associated with the
// file descriptor fd using the LOOP_SET_STATUS64 operation.
func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
}

View file

@ -156,10 +156,10 @@ openbsd_amd64)
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;; ;;
openbsd_arm) openbsd_arm)
mkasm="go run mkasm.go"
mkerrors="$mkerrors" mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -openbsd -arm" mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc"
mksysctl="go run mksysctl_openbsd.go" mksysctl="go run mksysctl_openbsd.go"
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall # Let the type of C char be signed for making the bare syscall
# API consistent across platforms. # API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
@ -182,6 +182,24 @@ openbsd_mips64)
# API consistent across platforms. # API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;; ;;
openbsd_ppc64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_riscv64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
solaris_amd64) solaris_amd64)
mksyscall="go run mksyscall_solaris.go" mksyscall="go run mksyscall_solaris.go"
mkerrors="$mkerrors -m64" mkerrors="$mkerrors -m64"
@ -214,11 +232,6 @@ esac
if [ "$GOOSARCH" == "aix_ppc64" ]; then if [ "$GOOSARCH" == "aix_ppc64" ]; then
# aix/ppc64 script generates files instead of writing to stdin. # aix/ppc64 script generates files instead of writing to stdin.
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ; echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
elif [ "$GOOS" == "darwin" ]; then
# 1.12 and later, syscalls via libSystem
echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
# 1.13 and later, syscalls via libSystem (including syscallPtr)
echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go";
elif [ "$GOOS" == "illumos" ]; then elif [ "$GOOS" == "illumos" ]; then
# illumos code generation requires a --illumos switch # illumos code generation requires a --illumos switch
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go"; echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";

View file

@ -642,7 +642,7 @@ errors=$(
signals=$( signals=$(
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
sort sort
) )
@ -652,7 +652,7 @@ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
sort >_error.grep sort >_error.grep
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' | grep -v 'SIGSTKSIZE\|SIGSTKSZ\|SIGRT\|SIGMAX64' |
sort >_signal.grep sort >_signal.grep
echo '// mkerrors.sh' "$@" echo '// mkerrors.sh' "$@"

27
vendor/golang.org/x/sys/unix/str.go generated vendored
View file

@ -1,27 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
if val < 0 {
return "-" + uitoa(uint(-val))
}
return uitoa(uint(val))
}
func uitoa(val uint) string {
var buf [32]byte // big enough for int64
i := len(buf) - 1
for val >= 10 {
buf[i] = byte(val%10 + '0')
i--
val /= 10
}
buf[i] = byte(val + '0')
return string(buf[i:])
}

View file

@ -29,8 +29,6 @@ import (
"bytes" "bytes"
"strings" "strings"
"unsafe" "unsafe"
"golang.org/x/sys/internal/unsafeheader"
) )
// ByteSliceFromString returns a NUL-terminated slice of bytes // ByteSliceFromString returns a NUL-terminated slice of bytes
@ -82,13 +80,7 @@ func BytePtrToString(p *byte) string {
ptr = unsafe.Pointer(uintptr(ptr) + 1) ptr = unsafe.Pointer(uintptr(ptr) + 1)
} }
var s []byte return string(unsafe.Slice(p, n))
h := (*unsafeheader.Slice)(unsafe.Pointer(&s))
h.Data = unsafe.Pointer(p)
h.Len = n
h.Cap = n
return string(s)
} }
// Single-word zero for use when we need a valid pointer to 0 bytes. // Single-word zero for use when we need a valid pointer to 0 bytes.

View file

@ -1,32 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin && go1.12 && !go1.13
// +build darwin,go1.12,!go1.13
package unix
import (
"unsafe"
)
const _SYS_GETDIRENTRIES64 = 344
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// To implement this using libSystem we'd need syscall_syscallPtr for
// fdopendir. However, syscallPtr was only added in Go 1.13, so we fall
// back to raw syscalls for this func on Go 1.12.
var p unsafe.Pointer
if len(buf) > 0 {
p = unsafe.Pointer(&buf[0])
} else {
p = unsafe.Pointer(&_zero)
}
r0, _, e1 := Syscall6(_SYS_GETDIRENTRIES64, uintptr(fd), uintptr(p), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
if e1 != 0 {
return n, errnoErr(e1)
}
return n, nil
}

View file

@ -1,108 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin && go1.13
// +build darwin,go1.13
package unix
import (
"unsafe"
"golang.org/x/sys/internal/unsafeheader"
)
//sys closedir(dir uintptr) (err error)
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
func fdopendir(fd int) (dir uintptr, err error) {
r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0)
dir = uintptr(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_fdopendir_trampoline_addr uintptr
//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// Simulate Getdirentries using fdopendir/readdir_r/closedir.
// We store the number of entries to skip in the seek
// offset of fd. See issue #31368.
// It's not the full required semantics, but should handle the case
// of calling Getdirentries or ReadDirent repeatedly.
// It won't handle assigning the results of lseek to *basep, or handle
// the directory being edited underfoot.
skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
if err != nil {
return 0, err
}
// We need to duplicate the incoming file descriptor
// because the caller expects to retain control of it, but
// fdopendir expects to take control of its argument.
// Just Dup'ing the file descriptor is not enough, as the
// result shares underlying state. Use Openat to make a really
// new file descriptor referring to the same directory.
fd2, err := Openat(fd, ".", O_RDONLY, 0)
if err != nil {
return 0, err
}
d, err := fdopendir(fd2)
if err != nil {
Close(fd2)
return 0, err
}
defer closedir(d)
var cnt int64
for {
var entry Dirent
var entryp *Dirent
e := readdir_r(d, &entry, &entryp)
if e != 0 {
return n, errnoErr(e)
}
if entryp == nil {
break
}
if skip > 0 {
skip--
cnt++
continue
}
reclen := int(entry.Reclen)
if reclen > len(buf) {
// Not enough room. Return for now.
// The counter will let us know where we should start up again.
// Note: this strategy for suspending in the middle and
// restarting is O(n^2) in the length of the directory. Oh well.
break
}
// Copy entry into return buffer.
var s []byte
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&s))
hdr.Data = unsafe.Pointer(&entry)
hdr.Cap = reclen
hdr.Len = reclen
copy(buf, s)
buf = buf[reclen:]
n += reclen
cnt++
}
// Set the seek offset of the input fd to record
// how many files we've already returned.
_, err = Seek(fd, cnt, 0 /* SEEK_SET */)
if err != nil {
return n, err
}
return n, nil
}

View file

@ -19,6 +19,96 @@ import (
"unsafe" "unsafe"
) )
//sys closedir(dir uintptr) (err error)
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
func fdopendir(fd int) (dir uintptr, err error) {
r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0)
dir = uintptr(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_fdopendir_trampoline_addr uintptr
//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
// Simulate Getdirentries using fdopendir/readdir_r/closedir.
// We store the number of entries to skip in the seek
// offset of fd. See issue #31368.
// It's not the full required semantics, but should handle the case
// of calling Getdirentries or ReadDirent repeatedly.
// It won't handle assigning the results of lseek to *basep, or handle
// the directory being edited underfoot.
skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
if err != nil {
return 0, err
}
// We need to duplicate the incoming file descriptor
// because the caller expects to retain control of it, but
// fdopendir expects to take control of its argument.
// Just Dup'ing the file descriptor is not enough, as the
// result shares underlying state. Use Openat to make a really
// new file descriptor referring to the same directory.
fd2, err := Openat(fd, ".", O_RDONLY, 0)
if err != nil {
return 0, err
}
d, err := fdopendir(fd2)
if err != nil {
Close(fd2)
return 0, err
}
defer closedir(d)
var cnt int64
for {
var entry Dirent
var entryp *Dirent
e := readdir_r(d, &entry, &entryp)
if e != 0 {
return n, errnoErr(e)
}
if entryp == nil {
break
}
if skip > 0 {
skip--
cnt++
continue
}
reclen := int(entry.Reclen)
if reclen > len(buf) {
// Not enough room. Return for now.
// The counter will let us know where we should start up again.
// Note: this strategy for suspending in the middle and
// restarting is O(n^2) in the length of the directory. Oh well.
break
}
// Copy entry into return buffer.
s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen)
copy(buf, s)
buf = buf[reclen:]
n += reclen
cnt++
}
// Set the seek offset of the input fd to record
// how many files we've already returned.
_, err = Seek(fd, cnt, 0 /* SEEK_SET */)
if err != nil {
return n, err
}
return n, nil
}
// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. // SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
type SockaddrDatalink struct { type SockaddrDatalink struct {
Len uint8 Len uint8

View file

@ -61,7 +61,7 @@ func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
} }
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint32(countin)} ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint32(countin)}
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
return int(ioDesc.Len), err return int(ioDesc.Len), err
} }

View file

@ -61,7 +61,7 @@ func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
} }
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)} ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
return int(ioDesc.Len), err return int(ioDesc.Len), err
} }

View file

@ -57,7 +57,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint32(countin)} ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint32(countin)}
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
return int(ioDesc.Len), err return int(ioDesc.Len), err
} }

View file

@ -57,7 +57,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)} ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
return int(ioDesc.Len), err return int(ioDesc.Len), err
} }

View file

@ -57,7 +57,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) { func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)} ioDesc := PtraceIoDesc{Op: int32(req), Offs: uintptr(unsafe.Pointer(addr)), Addr: uintptr(unsafe.Pointer(&out[0])), Len: uint64(countin)}
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0) err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
return int(ioDesc.Len), err return int(ioDesc.Len), err
} }

View file

@ -10,8 +10,6 @@
package unix package unix
import ( import (
"fmt"
"runtime"
"unsafe" "unsafe"
) )
@ -79,107 +77,3 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
} }
return return
} }
//sys putmsg(fd int, clptr *strbuf, dataptr *strbuf, flags int) (err error)
func Putmsg(fd int, cl []byte, data []byte, flags int) (err error) {
var clp, datap *strbuf
if len(cl) > 0 {
clp = &strbuf{
Len: int32(len(cl)),
Buf: (*int8)(unsafe.Pointer(&cl[0])),
}
}
if len(data) > 0 {
datap = &strbuf{
Len: int32(len(data)),
Buf: (*int8)(unsafe.Pointer(&data[0])),
}
}
return putmsg(fd, clp, datap, flags)
}
//sys getmsg(fd int, clptr *strbuf, dataptr *strbuf, flags *int) (err error)
func Getmsg(fd int, cl []byte, data []byte) (retCl []byte, retData []byte, flags int, err error) {
var clp, datap *strbuf
if len(cl) > 0 {
clp = &strbuf{
Maxlen: int32(len(cl)),
Buf: (*int8)(unsafe.Pointer(&cl[0])),
}
}
if len(data) > 0 {
datap = &strbuf{
Maxlen: int32(len(data)),
Buf: (*int8)(unsafe.Pointer(&data[0])),
}
}
if err = getmsg(fd, clp, datap, &flags); err != nil {
return nil, nil, 0, err
}
if len(cl) > 0 {
retCl = cl[:clp.Len]
}
if len(data) > 0 {
retData = data[:datap.Len]
}
return retCl, retData, flags, nil
}
func IoctlSetIntRetInt(fd int, req uint, arg int) (int, error) {
return ioctlRet(fd, req, uintptr(arg))
}
func IoctlSetString(fd int, req uint, val string) error {
bs := make([]byte, len(val)+1)
copy(bs[:len(bs)-1], val)
err := ioctl(fd, req, uintptr(unsafe.Pointer(&bs[0])))
runtime.KeepAlive(&bs[0])
return err
}
// Lifreq Helpers
func (l *Lifreq) SetName(name string) error {
if len(name) >= len(l.Name) {
return fmt.Errorf("name cannot be more than %d characters", len(l.Name)-1)
}
for i := range name {
l.Name[i] = int8(name[i])
}
return nil
}
func (l *Lifreq) SetLifruInt(d int) {
*(*int)(unsafe.Pointer(&l.Lifru[0])) = d
}
func (l *Lifreq) GetLifruInt() int {
return *(*int)(unsafe.Pointer(&l.Lifru[0]))
}
func (l *Lifreq) SetLifruUint(d uint) {
*(*uint)(unsafe.Pointer(&l.Lifru[0])) = d
}
func (l *Lifreq) GetLifruUint() uint {
return *(*uint)(unsafe.Pointer(&l.Lifru[0]))
}
func IoctlLifreq(fd int, req uint, l *Lifreq) error {
return ioctl(fd, req, uintptr(unsafe.Pointer(l)))
}
// Strioctl Helpers
func (s *Strioctl) SetInt(i int) {
s.Len = int32(unsafe.Sizeof(i))
s.Dp = (*int8)(unsafe.Pointer(&i))
}
func IoctlSetStrioctlRetInt(fd int, req uint, s *Strioctl) (int, error) {
return ioctlRet(fd, req, uintptr(unsafe.Pointer(s)))
}

View file

@ -13,6 +13,7 @@ package unix
import ( import (
"encoding/binary" "encoding/binary"
"strconv"
"syscall" "syscall"
"time" "time"
"unsafe" "unsafe"
@ -233,7 +234,7 @@ func Futimesat(dirfd int, path string, tv []Timeval) error {
func Futimes(fd int, tv []Timeval) (err error) { func Futimes(fd int, tv []Timeval) (err error) {
// Believe it or not, this is the best we can do on Linux // Believe it or not, this is the best we can do on Linux
// (and is what glibc does). // (and is what glibc does).
return Utimes("/proc/self/fd/"+itoa(fd), tv) return Utimes("/proc/self/fd/"+strconv.Itoa(fd), tv)
} }
const ImplementsGetwd = true const ImplementsGetwd = true
@ -1891,17 +1892,28 @@ func PrctlRetInt(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uint
return int(ret), nil return int(ret), nil
} }
// issue 1435.
// On linux Setuid and Setgid only affects the current thread, not the process.
// This does not match what most callers expect so we must return an error
// here rather than letting the caller think that the call succeeded.
func Setuid(uid int) (err error) { func Setuid(uid int) (err error) {
return EOPNOTSUPP return syscall.Setuid(uid)
} }
func Setgid(uid int) (err error) { func Setgid(gid int) (err error) {
return EOPNOTSUPP return syscall.Setgid(gid)
}
func Setreuid(ruid, euid int) (err error) {
return syscall.Setreuid(ruid, euid)
}
func Setregid(rgid, egid int) (err error) {
return syscall.Setregid(rgid, egid)
}
func Setresuid(ruid, euid, suid int) (err error) {
return syscall.Setresuid(ruid, euid, suid)
}
func Setresgid(rgid, egid, sgid int) (err error) {
return syscall.Setresgid(rgid, egid, sgid)
} }
// SetfsgidRetGid sets fsgid for current thread and returns previous fsgid set. // SetfsgidRetGid sets fsgid for current thread and returns previous fsgid set.
@ -2240,7 +2252,7 @@ func (fh *FileHandle) Bytes() []byte {
if n == 0 { if n == 0 {
return nil return nil
} }
return (*[1 << 30]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type)) + 4))[:n:n] return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type))+4)), n)
} }
// NameToHandleAt wraps the name_to_handle_at system call; it obtains // NameToHandleAt wraps the name_to_handle_at system call; it obtains
@ -2356,6 +2368,16 @@ func Setitimer(which ItimerWhich, it Itimerval) (Itimerval, error) {
return prev, nil return prev, nil
} }
//sysnb rtSigprocmask(how int, set *Sigset_t, oldset *Sigset_t, sigsetsize uintptr) (err error) = SYS_RT_SIGPROCMASK
func PthreadSigmask(how int, set, oldset *Sigset_t) error {
if oldset != nil {
// Explicitly clear in case Sigset_t is larger than _C__NSIG.
*oldset = Sigset_t{}
}
return rtSigprocmask(how, set, oldset, _C__NSIG/8)
}
/* /*
* Unimplemented * Unimplemented
*/ */
@ -2414,7 +2436,6 @@ func Setitimer(which ItimerWhich, it Itimerval) (Itimerval, error) {
// RestartSyscall // RestartSyscall
// RtSigaction // RtSigaction
// RtSigpending // RtSigpending
// RtSigprocmask
// RtSigqueueinfo // RtSigqueueinfo
// RtSigreturn // RtSigreturn
// RtSigsuspend // RtSigsuspend

View file

@ -41,10 +41,6 @@ func setTimeval(sec, usec int64) Timeval {
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64 //sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
//sys setfsgid(gid int) (prev int, err error) = SYS_SETFSGID32 //sys setfsgid(gid int) (prev int, err error) = SYS_SETFSGID32
//sys setfsuid(uid int) (prev int, err error) = SYS_SETFSUID32 //sys setfsuid(uid int) (prev int, err error) = SYS_SETFSUID32
//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID32
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) = SYS_SETRESGID32
//sysnb Setresuid(ruid int, euid int, suid int) (err error) = SYS_SETRESUID32
//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID32
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)

Some files were not shown because too many files have changed in this diff Show more