| @@ -74,6 +74,23 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] | |||||
| ; List of reasons why a Pull Request or Issue can be locked | ; List of reasons why a Pull Request or Issue can be locked | ||||
| LOCK_REASONS=Too heated,Off-topic,Resolved,Spam | LOCK_REASONS=Too heated,Off-topic,Resolved,Spam | ||||
| [cors] | |||||
| ; More information about CORS can be found here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers | |||||
| ; enable cors headers (disabled by default) | |||||
| ENABLED=false | |||||
| ; scheme of allowed requests | |||||
| SCHEME=http | |||||
| ; list of requesting domains that are allowed | |||||
| ALLOW_DOMAIN=* | |||||
| ; allow subdomains of headers listed above to request | |||||
| ALLOW_SUBDOMAIN=false | |||||
| ; list of methods allowed to request | |||||
| METHODS=GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS | |||||
| ; max time to cache response | |||||
| MAX_AGE=10m | |||||
| ; allow request with credentials | |||||
| ALLOW_CREDENTIALS=false | |||||
| [ui] | [ui] | ||||
| ; Number of repositories that are displayed on one explore page | ; Number of repositories that are displayed on one explore page | ||||
| EXPLORE_PAGING_NUM = 20 | EXPLORE_PAGING_NUM = 20 | ||||
| @@ -76,6 +76,16 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. | |||||
| - `LOCK_REASONS`: **Too heated,Off-topic,Resolved,Spam**: A list of reasons why a Pull Request or Issue can be locked | - `LOCK_REASONS`: **Too heated,Off-topic,Resolved,Spam**: A list of reasons why a Pull Request or Issue can be locked | ||||
| ## CORS (`cors`) | |||||
| - `ENABLED`: **false**: enable cors headers (disabled by default) | |||||
| - `SCHEME`: **http**: scheme of allowed requests | |||||
| - `ALLOW_DOMAIN`: **\***: list of requesting domains that are allowed | |||||
| - `ALLOW_SUBDOMAIN`: **false**: allow subdomains of headers listed above to request | |||||
| - `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request | |||||
| - `MAX_AGE`: **10m**: max time to cache response | |||||
| - `ALLOW_CREDENTIALS`: **false**: allow request with credentials | |||||
| ## UI (`ui`) | ## UI (`ui`) | ||||
| - `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page. | - `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page. | ||||
| @@ -7,7 +7,7 @@ require ( | |||||
| github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 | github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 | ||||
| github.com/RoaringBitmap/roaring v0.4.7 // indirect | github.com/RoaringBitmap/roaring v0.4.7 // indirect | ||||
| github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca | github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca | ||||
| github.com/Unknwon/com v0.0.0-20170819223952-7677a1d7c113 | |||||
| github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 | |||||
| github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 | github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 | ||||
| github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 | github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 | ||||
| github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 // indirect | github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 // indirect | ||||
| @@ -48,6 +48,7 @@ require ( | |||||
| github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 | github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 | ||||
| github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 | github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 | ||||
| github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab | github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab | ||||
| github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 | |||||
| github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 | github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 | ||||
| github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f | github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f | ||||
| github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 | github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 | ||||
| @@ -113,17 +114,17 @@ require ( | |||||
| github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect | github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect | ||||
| github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 | github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 | ||||
| go.etcd.io/bbolt v1.3.2 // indirect | go.etcd.io/bbolt v1.3.2 // indirect | ||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 | |||||
| golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 | |||||
| golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 | ||||
| golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 | golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 | ||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 | |||||
| golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e | |||||
| golang.org/x/text v0.3.0 | golang.org/x/text v0.3.0 | ||||
| gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect | gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect | ||||
| gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | ||||
| gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect | gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect | ||||
| gopkg.in/editorconfig/editorconfig-core-go.v1 v1.2.0 | gopkg.in/editorconfig/editorconfig-core-go.v1 v1.2.0 | ||||
| gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df | ||||
| gopkg.in/ini.v1 v1.31.1 | |||||
| gopkg.in/ini.v1 v1.42.0 | |||||
| gopkg.in/ldap.v3 v3.0.2 | gopkg.in/ldap.v3 v3.0.2 | ||||
| gopkg.in/macaron.v1 v1.3.2 | gopkg.in/macaron.v1 v1.3.2 | ||||
| gopkg.in/redis.v2 v2.3.2 // indirect | gopkg.in/redis.v2 v2.3.2 // indirect | ||||
| @@ -135,6 +136,6 @@ require ( | |||||
| ) | ) | ||||
| replace ( | replace ( | ||||
| github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 | |||||
| github.com/go-sql-driver/mysql v1.4.0 => github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f | |||||
| github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 | |||||
| github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f | |||||
| ) | ) | ||||
| @@ -7,8 +7,8 @@ github.com/RoaringBitmap/roaring v0.4.7 h1:eGUudvFzvF7Kxh7JjYvXfI1f7l22/2duFby7r | |||||
| github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= | github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= | ||||
| github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca h1:xU8R31tsvj6TesCBog973+UgI3TXjh/LqN5clki6hcc= | github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca h1:xU8R31tsvj6TesCBog973+UgI3TXjh/LqN5clki6hcc= | ||||
| github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca/go.mod h1:IRSre9/SEhVuy972TVuJLyaPTS73+8Owhe0Y0l9NXHc= | github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca/go.mod h1:IRSre9/SEhVuy972TVuJLyaPTS73+8Owhe0Y0l9NXHc= | ||||
| github.com/Unknwon/com v0.0.0-20170819223952-7677a1d7c113 h1:YwXm6KwmrA5R5yJRhcnpqRUHmBXSKciHuWtK9zP5qKQ= | |||||
| github.com/Unknwon/com v0.0.0-20170819223952-7677a1d7c113/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no= | |||||
| github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= | |||||
| github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= | |||||
| github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 h1:Mp8GNJ/tdTZIEdLdZfykEJaL3mTyEYrSzYNcdoQKpJk= | github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 h1:Mp8GNJ/tdTZIEdLdZfykEJaL3mTyEYrSzYNcdoQKpJk= | ||||
| github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966/go.mod h1:SFtfq0zFPsENI7DpE87QM2hcYu5QQ0fRdCgP+P1Hrqo= | github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966/go.mod h1:SFtfq0zFPsENI7DpE87QM2hcYu5QQ0fRdCgP+P1Hrqo= | ||||
| github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 h1:SSvHGK7iMpeypcHjI8UzNMz7zW/K8/dcgqk/82lCYP0= | github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 h1:SSvHGK7iMpeypcHjI8UzNMz7zW/K8/dcgqk/82lCYP0= | ||||
| @@ -105,6 +105,8 @@ github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5 | |||||
| github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok= | github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok= | ||||
| github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI= | github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI= | ||||
| github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA= | github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA= | ||||
| github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8= | |||||
| github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E= | |||||
| github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo= | github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo= | ||||
| github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372/go.mod h1:oZGMxI7MBnicI0jJqJvH4qQzyrWKhtiKxLSJKHC+ydc= | github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372/go.mod h1:oZGMxI7MBnicI0jJqJvH4qQzyrWKhtiKxLSJKHC+ydc= | ||||
| github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f h1:wDKrZFc9pYJlqFOf7EzGbFMrSFFtyHt3plr2uTdo8Rg= | github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f h1:wDKrZFc9pYJlqFOf7EzGbFMrSFFtyHt3plr2uTdo8Rg= | ||||
| @@ -148,6 +150,8 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu | |||||
| github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||||
| github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||||
| github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= | github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= | ||||
| github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | ||||
| github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= | github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= | ||||
| @@ -178,6 +182,7 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U | |||||
| github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= | github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= | ||||
| github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= | github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= | ||||
| github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= | ||||
| github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||||
| github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | ||||
| github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | ||||
| github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7cCpiRVEIr1B5ccDxRpbPsWT5JU3if2Di5nE4= | github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7cCpiRVEIr1B5ccDxRpbPsWT5JU3if2Di5nE4= | ||||
| @@ -281,6 +286,9 @@ github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7 | |||||
| github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | ||||
| github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= | ||||
| github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | ||||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||||
| github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||||
| github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys= | github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys= | ||||
| github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= | github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= | ||||
| github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= | github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= | ||||
| @@ -316,6 +324,8 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= | |||||
| golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= | ||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk= | |||||
| golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= | |||||
| 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= | ||||
| @@ -332,6 +342,8 @@ golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5h | |||||
| 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-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= | ||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= | |||||
| golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||||
| 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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| @@ -353,8 +365,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | |||||
| gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | ||||
| gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= | ||||
| gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= | ||||
| gopkg.in/ini.v1 v1.31.1 h1:8EY/6KDwKM9Qg4vu1+01ZpsxClC/XV71R+nZ/TL7D4M= | |||||
| gopkg.in/ini.v1 v1.31.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||||
| gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= | |||||
| gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||||
| gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= | gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= | ||||
| gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= | gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= | ||||
| gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= | gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= | ||||
| @@ -0,0 +1,22 @@ | |||||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||||
| // Use of this source code is governed by a MIT-style | |||||
| // license that can be found in the LICENSE file. | |||||
| package integrations | |||||
| import ( | |||||
| "net/http" | |||||
| "testing" | |||||
| "github.com/stretchr/testify/assert" | |||||
| ) | |||||
| func TestCORSNotSet(t *testing.T) { | |||||
| prepareTestEnv(t) | |||||
| req := NewRequestf(t, "GET", "/api/v1/version") | |||||
| session := loginUser(t, "user2") | |||||
| resp := session.MakeRequest(t, req, http.StatusOK) | |||||
| assert.Equal(t, resp.Code, http.StatusOK) | |||||
| corsHeader := resp.Header().Get("Access-Control-Allow-Origin") | |||||
| assert.Equal(t, corsHeader, "", "Access-Control-Allow-Origin: generated header should match") // header not set | |||||
| } | |||||
| @@ -0,0 +1,41 @@ | |||||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||||
| // Use of this source code is governed by a MIT-style | |||||
| // license that can be found in the LICENSE file. | |||||
| package setting | |||||
| import ( | |||||
| "time" | |||||
| "code.gitea.io/gitea/modules/log" | |||||
| "github.com/go-macaron/cors" | |||||
| ) | |||||
| var ( | |||||
| // CORSConfig defines CORS settings | |||||
| CORSConfig cors.Options | |||||
| // EnableCORS defines whether CORS settings is enabled or not | |||||
| EnableCORS bool | |||||
| ) | |||||
| func newCORSService() { | |||||
| sec := Cfg.Section("cors") | |||||
| // Check cors setting. | |||||
| EnableCORS = sec.Key("ENABLED").MustBool(false) | |||||
| maxAge := sec.Key("MAX_AGE").MustDuration(10 * time.Minute) | |||||
| CORSConfig = cors.Options{ | |||||
| Scheme: sec.Key("SCHEME").String(), | |||||
| AllowDomain: sec.Key("ALLOW_DOMAIN").String(), | |||||
| AllowSubdomain: sec.Key("ALLOW_SUBDOMAIN").MustBool(), | |||||
| Methods: sec.Key("METHODS").Strings(","), | |||||
| MaxAgeSeconds: int(maxAge.Seconds()), | |||||
| AllowCredentials: sec.Key("ALLOW_CREDENTIALS").MustBool(), | |||||
| } | |||||
| if EnableCORS { | |||||
| log.Info("CORS Service Enabled") | |||||
| } | |||||
| } | |||||
| @@ -1006,6 +1006,7 @@ func NewServices() { | |||||
| NewLogServices(false) | NewLogServices(false) | ||||
| newCacheService() | newCacheService() | ||||
| newSessionService() | newSessionService() | ||||
| newCORSService() | |||||
| newMailService() | newMailService() | ||||
| newRegisterMailService() | newRegisterMailService() | ||||
| newNotifyMailService() | newNotifyMailService() | ||||
| @@ -74,7 +74,8 @@ import ( | |||||
| "code.gitea.io/gitea/routers/api/v1/user" | "code.gitea.io/gitea/routers/api/v1/user" | ||||
| "github.com/go-macaron/binding" | "github.com/go-macaron/binding" | ||||
| "gopkg.in/macaron.v1" | |||||
| "github.com/go-macaron/cors" | |||||
| macaron "gopkg.in/macaron.v1" | |||||
| ) | ) | ||||
| func sudo() macaron.Handler { | func sudo() macaron.Handler { | ||||
| @@ -500,6 +501,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/swagger", misc.Swagger) //Render V1 by default | m.Get("/swagger", misc.Swagger) //Render V1 by default | ||||
| } | } | ||||
| var handlers []macaron.Handler | |||||
| if setting.EnableCORS { | |||||
| handlers = append(handlers, cors.CORS(setting.CORSConfig)) | |||||
| } | |||||
| handlers = append(handlers, securityHeaders(), context.APIContexter(), sudo()) | |||||
| m.Group("/v1", func() { | m.Group("/v1", func() { | ||||
| // Miscellaneous | // Miscellaneous | ||||
| if setting.API.EnableSwagger { | if setting.API.EnableSwagger { | ||||
| @@ -841,5 +848,15 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Group("/topics", func() { | m.Group("/topics", func() { | ||||
| m.Get("/search", repo.TopicSearch) | m.Get("/search", repo.TopicSearch) | ||||
| }) | }) | ||||
| }, context.APIContexter(), sudo()) | |||||
| }, handlers...) | |||||
| } | |||||
| func securityHeaders() macaron.Handler { | |||||
| return func(ctx *macaron.Context) { | |||||
| ctx.Resp.Before(func(w macaron.ResponseWriter) { | |||||
| // CORB: https://www.chromium.org/Home/chromium-security/corb-for-developers | |||||
| // http://stackoverflow.com/a/3146618/244009 | |||||
| w.Header().Set("x-content-type-options", "nosniff") | |||||
| }) | |||||
| } | |||||
| } | } | ||||
| @@ -32,7 +32,7 @@ func IsDir(dir string) bool { | |||||
| return f.IsDir() | return f.IsDir() | ||||
| } | } | ||||
| func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, error) { | |||||
| func statDir(dirPath, recPath string, includeDir, isDirOnly, followSymlinks bool) ([]string, error) { | |||||
| dir, err := os.Open(dirPath) | dir, err := os.Open(dirPath) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| @@ -56,13 +56,29 @@ func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, err | |||||
| if includeDir { | if includeDir { | ||||
| statList = append(statList, relPath+"/") | statList = append(statList, relPath+"/") | ||||
| } | } | ||||
| s, err := statDir(curPath, relPath, includeDir, isDirOnly) | |||||
| s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| statList = append(statList, s...) | statList = append(statList, s...) | ||||
| } else if !isDirOnly { | } else if !isDirOnly { | ||||
| statList = append(statList, relPath) | statList = append(statList, relPath) | ||||
| } else if followSymlinks && fi.Mode()&os.ModeSymlink != 0 { | |||||
| link, err := os.Readlink(curPath) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if IsDir(link) { | |||||
| if includeDir { | |||||
| statList = append(statList, relPath+"/") | |||||
| } | |||||
| s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| statList = append(statList, s...) | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| return statList, nil | return statList, nil | ||||
| @@ -84,7 +100,26 @@ func StatDir(rootPath string, includeDir ...bool) ([]string, error) { | |||||
| if len(includeDir) >= 1 { | if len(includeDir) >= 1 { | ||||
| isIncludeDir = includeDir[0] | isIncludeDir = includeDir[0] | ||||
| } | } | ||||
| return statDir(rootPath, "", isIncludeDir, false) | |||||
| return statDir(rootPath, "", isIncludeDir, false, false) | |||||
| } | |||||
| // LstatDir gathers information of given directory by depth-first. | |||||
| // It returns slice of file list, follows symbolic links and includes subdirectories if enabled; | |||||
| // it returns error and nil slice when error occurs in underlying functions, | |||||
| // or given path is not a directory or does not exist. | |||||
| // | |||||
| // Slice does not include given path itself. | |||||
| // If subdirectories is enabled, they will have suffix '/'. | |||||
| func LstatDir(rootPath string, includeDir ...bool) ([]string, error) { | |||||
| if !IsDir(rootPath) { | |||||
| return nil, errors.New("not a directory or does not exist: " + rootPath) | |||||
| } | |||||
| isIncludeDir := false | |||||
| if len(includeDir) >= 1 { | |||||
| isIncludeDir = includeDir[0] | |||||
| } | |||||
| return statDir(rootPath, "", isIncludeDir, false, true) | |||||
| } | } | ||||
| // GetAllSubDirs returns all subdirectories of given root path. | // GetAllSubDirs returns all subdirectories of given root path. | ||||
| @@ -93,7 +128,17 @@ func GetAllSubDirs(rootPath string) ([]string, error) { | |||||
| if !IsDir(rootPath) { | if !IsDir(rootPath) { | ||||
| return nil, errors.New("not a directory or does not exist: " + rootPath) | return nil, errors.New("not a directory or does not exist: " + rootPath) | ||||
| } | } | ||||
| return statDir(rootPath, "", true, true) | |||||
| return statDir(rootPath, "", true, true, false) | |||||
| } | |||||
| // LgetAllSubDirs returns all subdirectories of given root path, including | |||||
| // following symbolic links, if any. | |||||
| // Slice does not include given path itself. | |||||
| func LgetAllSubDirs(rootPath string) ([]string, error) { | |||||
| if !IsDir(rootPath) { | |||||
| return nil, errors.New("not a directory or does not exist: " + rootPath) | |||||
| } | |||||
| return statDir(rootPath, "", true, true, true) | |||||
| } | } | ||||
| // GetFileListBySuffix returns an ordered list of file paths. | // GetFileListBySuffix returns an ordered list of file paths. | ||||
| @@ -0,0 +1,8 @@ | |||||
| module github.com/Unknwon/com | |||||
| require ( | |||||
| github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect | |||||
| github.com/jtolds/gls v4.2.1+incompatible // indirect | |||||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect | |||||
| github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c | |||||
| ) | |||||
| @@ -0,0 +1,8 @@ | |||||
| github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||||
| github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||||
| github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= | |||||
| github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||||
| github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= | |||||
| github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||||
| @@ -36,7 +36,7 @@ func HtmlEncode(str string) string { | |||||
| return html.EscapeString(str) | return html.EscapeString(str) | ||||
| } | } | ||||
| // decode string to html chars | |||||
| // HtmlDecode decodes string to html chars | |||||
| func HtmlDecode(str string) string { | func HtmlDecode(str string) string { | ||||
| return html.UnescapeString(str) | return html.UnescapeString(str) | ||||
| } | } | ||||
| @@ -177,7 +177,7 @@ func FetchFiles(client *http.Client, files []RawFile, header http.Header) error | |||||
| return nil | return nil | ||||
| } | } | ||||
| // FetchFiles uses command `curl` to fetch files specified by the rawURL field in parallel. | |||||
| // FetchFilesCurl uses command `curl` to fetch files specified by the rawURL field in parallel. | |||||
| func FetchFilesCurl(files []RawFile, curlOptions ...string) error { | func FetchFilesCurl(files []RawFile, curlOptions ...string) error { | ||||
| ch := make(chan error, len(files)) | ch := make(chan error, len(files)) | ||||
| for i := range files { | for i := range files { | ||||
| @@ -14,12 +14,12 @@ | |||||
| package com | package com | ||||
| // PowInt is int type of math.Pow function. | |||||
| // PowInt is int type of math.Pow function. | |||||
| func PowInt(x int, y int) int { | func PowInt(x int, y int) int { | ||||
| if y <= 0 { | if y <= 0 { | ||||
| return 1 | return 1 | ||||
| } else { | } else { | ||||
| if y % 2 == 0 { | |||||
| if y%2 == 0 { | |||||
| sqrt := PowInt(x, y/2) | sqrt := PowInt(x, y/2) | ||||
| return sqrt * sqrt | return sqrt * sqrt | ||||
| } else { | } else { | ||||
| @@ -37,19 +37,19 @@ func init() { | |||||
| regex_url = regexp.MustCompile(regex_url_pattern) | regex_url = regexp.MustCompile(regex_url_pattern) | ||||
| } | } | ||||
| // validate string is an email address, if not return false | |||||
| // IsEmail validates string is an email address, if not return false | |||||
| // basically validation can match 99% cases | // basically validation can match 99% cases | ||||
| func IsEmail(email string) bool { | func IsEmail(email string) bool { | ||||
| return regex_email.MatchString(email) | return regex_email.MatchString(email) | ||||
| } | } | ||||
| // validate string is an email address, if not return false | |||||
| // IsEmailRFC validates string is an email address, if not return false | |||||
| // this validation omits RFC 2822 | // this validation omits RFC 2822 | ||||
| func IsEmailRFC(email string) bool { | func IsEmailRFC(email string) bool { | ||||
| return regex_strict_email.MatchString(email) | return regex_strict_email.MatchString(email) | ||||
| } | } | ||||
| // validate string is a url link, if not return false | |||||
| // IsUrl validates string is a url link, if not return false | |||||
| // simple validation can match 99% cases | // simple validation can match 99% cases | ||||
| func IsUrl(url string) bool { | func IsUrl(url string) bool { | ||||
| return regex_url.MatchString(url) | return regex_url.MatchString(url) | ||||
| @@ -44,7 +44,7 @@ func CompareSliceStr(s1, s2 []string) bool { | |||||
| return true | return true | ||||
| } | } | ||||
| // CompareSliceStr compares two 'string' type slices. | |||||
| // CompareSliceStrU compares two 'string' type slices. | |||||
| // It returns true if elements are the same, and ignores the order. | // It returns true if elements are the same, and ignores the order. | ||||
| func CompareSliceStrU(s1, s2 []string) bool { | func CompareSliceStrU(s1, s2 []string) bool { | ||||
| if len(s1) != len(s2) { | if len(s1) != len(s2) { | ||||
| @@ -0,0 +1,12 @@ | |||||
| # Binaries for programs and plugins | |||||
| *.exe | |||||
| *.exe~ | |||||
| *.dll | |||||
| *.so | |||||
| *.dylib | |||||
| # Test binary, build with `go test -c` | |||||
| *.test | |||||
| # Output of the go coverage tool, specifically when used with LiteIDE | |||||
| *.out | |||||
| @@ -0,0 +1,201 @@ | |||||
| Apache License | |||||
| Version 2.0, January 2004 | |||||
| http://www.apache.org/licenses/ | |||||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||||
| 1. Definitions. | |||||
| "License" shall mean the terms and conditions for use, reproduction, | |||||
| and distribution as defined by Sections 1 through 9 of this document. | |||||
| "Licensor" shall mean the copyright owner or entity authorized by | |||||
| the copyright owner that is granting the License. | |||||
| "Legal Entity" shall mean the union of the acting entity and all | |||||
| other entities that control, are controlled by, or are under common | |||||
| control with that entity. For the purposes of this definition, | |||||
| "control" means (i) the power, direct or indirect, to cause the | |||||
| direction or management of such entity, whether by contract or | |||||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||||
| outstanding shares, or (iii) beneficial ownership of such entity. | |||||
| "You" (or "Your") shall mean an individual or Legal Entity | |||||
| exercising permissions granted by this License. | |||||
| "Source" form shall mean the preferred form for making modifications, | |||||
| including but not limited to software source code, documentation | |||||
| source, and configuration files. | |||||
| "Object" form shall mean any form resulting from mechanical | |||||
| transformation or translation of a Source form, including but | |||||
| not limited to compiled object code, generated documentation, | |||||
| and conversions to other media types. | |||||
| "Work" shall mean the work of authorship, whether in Source or | |||||
| Object form, made available under the License, as indicated by a | |||||
| copyright notice that is included in or attached to the work | |||||
| (an example is provided in the Appendix below). | |||||
| "Derivative Works" shall mean any work, whether in Source or Object | |||||
| form, that is based on (or derived from) the Work and for which the | |||||
| editorial revisions, annotations, elaborations, or other modifications | |||||
| represent, as a whole, an original work of authorship. For the purposes | |||||
| of this License, Derivative Works shall not include works that remain | |||||
| separable from, or merely link (or bind by name) to the interfaces of, | |||||
| the Work and Derivative Works thereof. | |||||
| "Contribution" shall mean any work of authorship, including | |||||
| the original version of the Work and any modifications or additions | |||||
| to that Work or Derivative Works thereof, that is intentionally | |||||
| submitted to Licensor for inclusion in the Work by the copyright owner | |||||
| or by an individual or Legal Entity authorized to submit on behalf of | |||||
| the copyright owner. For the purposes of this definition, "submitted" | |||||
| means any form of electronic, verbal, or written communication sent | |||||
| to the Licensor or its representatives, including but not limited to | |||||
| communication on electronic mailing lists, source code control systems, | |||||
| and issue tracking systems that are managed by, or on behalf of, the | |||||
| Licensor for the purpose of discussing and improving the Work, but | |||||
| excluding communication that is conspicuously marked or otherwise | |||||
| designated in writing by the copyright owner as "Not a Contribution." | |||||
| "Contributor" shall mean Licensor and any individual or Legal Entity | |||||
| on behalf of whom a Contribution has been received by Licensor and | |||||
| subsequently incorporated within the Work. | |||||
| 2. Grant of Copyright License. Subject to the terms and conditions of | |||||
| this License, each Contributor hereby grants to You a perpetual, | |||||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||||
| copyright license to reproduce, prepare Derivative Works of, | |||||
| publicly display, publicly perform, sublicense, and distribute the | |||||
| Work and such Derivative Works in Source or Object form. | |||||
| 3. Grant of Patent License. Subject to the terms and conditions of | |||||
| this License, each Contributor hereby grants to You a perpetual, | |||||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||||
| (except as stated in this section) patent license to make, have made, | |||||
| use, offer to sell, sell, import, and otherwise transfer the Work, | |||||
| where such license applies only to those patent claims licensable | |||||
| by such Contributor that are necessarily infringed by their | |||||
| Contribution(s) alone or by combination of their Contribution(s) | |||||
| with the Work to which such Contribution(s) was submitted. If You | |||||
| institute patent litigation against any entity (including a | |||||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | |||||
| or a Contribution incorporated within the Work constitutes direct | |||||
| or contributory patent infringement, then any patent licenses | |||||
| granted to You under this License for that Work shall terminate | |||||
| as of the date such litigation is filed. | |||||
| 4. Redistribution. You may reproduce and distribute copies of the | |||||
| Work or Derivative Works thereof in any medium, with or without | |||||
| modifications, and in Source or Object form, provided that You | |||||
| meet the following conditions: | |||||
| (a) You must give any other recipients of the Work or | |||||
| Derivative Works a copy of this License; and | |||||
| (b) You must cause any modified files to carry prominent notices | |||||
| stating that You changed the files; and | |||||
| (c) You must retain, in the Source form of any Derivative Works | |||||
| that You distribute, all copyright, patent, trademark, and | |||||
| attribution notices from the Source form of the Work, | |||||
| excluding those notices that do not pertain to any part of | |||||
| the Derivative Works; and | |||||
| (d) If the Work includes a "NOTICE" text file as part of its | |||||
| distribution, then any Derivative Works that You distribute must | |||||
| include a readable copy of the attribution notices contained | |||||
| within such NOTICE file, excluding those notices that do not | |||||
| pertain to any part of the Derivative Works, in at least one | |||||
| of the following places: within a NOTICE text file distributed | |||||
| as part of the Derivative Works; within the Source form or | |||||
| documentation, if provided along with the Derivative Works; or, | |||||
| within a display generated by the Derivative Works, if and | |||||
| wherever such third-party notices normally appear. The contents | |||||
| of the NOTICE file are for informational purposes only and | |||||
| do not modify the License. You may add Your own attribution | |||||
| notices within Derivative Works that You distribute, alongside | |||||
| or as an addendum to the NOTICE text from the Work, provided | |||||
| that such additional attribution notices cannot be construed | |||||
| as modifying the License. | |||||
| You may add Your own copyright statement to Your modifications and | |||||
| may provide additional or different license terms and conditions | |||||
| for use, reproduction, or distribution of Your modifications, or | |||||
| for any such Derivative Works as a whole, provided Your use, | |||||
| reproduction, and distribution of the Work otherwise complies with | |||||
| the conditions stated in this License. | |||||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | |||||
| any Contribution intentionally submitted for inclusion in the Work | |||||
| by You to the Licensor shall be under the terms and conditions of | |||||
| this License, without any additional terms or conditions. | |||||
| Notwithstanding the above, nothing herein shall supersede or modify | |||||
| the terms of any separate license agreement you may have executed | |||||
| with Licensor regarding such Contributions. | |||||
| 6. Trademarks. This License does not grant permission to use the trade | |||||
| names, trademarks, service marks, or product names of the Licensor, | |||||
| except as required for reasonable and customary use in describing the | |||||
| origin of the Work and reproducing the content of the NOTICE file. | |||||
| 7. Disclaimer of Warranty. Unless required by applicable law or | |||||
| agreed to in writing, Licensor provides the Work (and each | |||||
| Contributor provides its Contributions) on an "AS IS" BASIS, | |||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||||
| implied, including, without limitation, any warranties or conditions | |||||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||||
| PARTICULAR PURPOSE. You are solely responsible for determining the | |||||
| appropriateness of using or redistributing the Work and assume any | |||||
| risks associated with Your exercise of permissions under this License. | |||||
| 8. Limitation of Liability. In no event and under no legal theory, | |||||
| whether in tort (including negligence), contract, or otherwise, | |||||
| unless required by applicable law (such as deliberate and grossly | |||||
| negligent acts) or agreed to in writing, shall any Contributor be | |||||
| liable to You for damages, including any direct, indirect, special, | |||||
| incidental, or consequential damages of any character arising as a | |||||
| result of this License or out of the use or inability to use the | |||||
| Work (including but not limited to damages for loss of goodwill, | |||||
| work stoppage, computer failure or malfunction, or any and all | |||||
| other commercial damages or losses), even if such Contributor | |||||
| has been advised of the possibility of such damages. | |||||
| 9. Accepting Warranty or Additional Liability. While redistributing | |||||
| the Work or Derivative Works thereof, You may choose to offer, | |||||
| and charge a fee for, acceptance of support, warranty, indemnity, | |||||
| or other liability obligations and/or rights consistent with this | |||||
| License. However, in accepting such obligations, You may act only | |||||
| on Your own behalf and on Your sole responsibility, not on behalf | |||||
| of any other Contributor, and only if You agree to indemnify, | |||||
| defend, and hold each Contributor harmless for any liability | |||||
| incurred by, or claims asserted against, such Contributor by reason | |||||
| of your accepting any such warranty or additional liability. | |||||
| END OF TERMS AND CONDITIONS | |||||
| APPENDIX: How to apply the Apache License to your work. | |||||
| To apply the Apache License to your work, attach the following | |||||
| boilerplate notice, with the fields enclosed by brackets "[]" | |||||
| replaced with your own identifying information. (Don't include | |||||
| the brackets!) The text should be enclosed in the appropriate | |||||
| comment syntax for the file format. We also recommend that a | |||||
| file or class name and description of purpose be included on the | |||||
| same "printed page" as the copyright notice for easier | |||||
| identification within third-party archives. | |||||
| Copyright [yyyy] [name of copyright owner] | |||||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||||
| you may not use this file except in compliance with the License. | |||||
| You may obtain a copy of the License at | |||||
| http://www.apache.org/licenses/LICENSE-2.0 | |||||
| Unless required by applicable law or agreed to in writing, software | |||||
| distributed under the License is distributed on an "AS IS" BASIS, | |||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
| See the License for the specific language governing permissions and | |||||
| limitations under the License. | |||||
| @@ -0,0 +1,2 @@ | |||||
| # cors | |||||
| Package cors is a middleware that handles CORS requests & headers for Macaron. | |||||
| @@ -0,0 +1,139 @@ | |||||
| package cors | |||||
| import ( | |||||
| "fmt" | |||||
| "log" | |||||
| "net/http" | |||||
| "net/url" | |||||
| "strconv" | |||||
| "strings" | |||||
| macaron "gopkg.in/macaron.v1" | |||||
| ) | |||||
| const _VERSION = "0.1.0" | |||||
| func Version() string { | |||||
| return _VERSION | |||||
| } | |||||
| // Options represents a struct for specifying configuration options for the CORS middleware. | |||||
| type Options struct { | |||||
| Section string | |||||
| Scheme string | |||||
| AllowDomain string | |||||
| AllowSubdomain bool | |||||
| Methods []string | |||||
| MaxAgeSeconds int | |||||
| AllowCredentials bool | |||||
| } | |||||
| func prepareOptions(options []Options) Options { | |||||
| var opt Options | |||||
| if len(options) > 0 { | |||||
| opt = options[0] | |||||
| } | |||||
| if len(opt.Section) == 0 { | |||||
| opt.Section = "cors" | |||||
| } | |||||
| sec := macaron.Config().Section(opt.Section) | |||||
| if len(opt.Scheme) == 0 { | |||||
| opt.Scheme = sec.Key("SCHEME").MustString("http") | |||||
| } | |||||
| if len(opt.AllowDomain) == 0 { | |||||
| opt.AllowDomain = sec.Key("ALLOW_DOMAIN").MustString("*") | |||||
| } | |||||
| if !opt.AllowSubdomain { | |||||
| opt.AllowSubdomain = sec.Key("ALLOW_SUBDOMAIN").MustBool(false) | |||||
| } | |||||
| if len(opt.Methods) == 0 { | |||||
| opt.Methods = sec.Key("METHODS").Strings(",") | |||||
| if len(opt.Methods) == 0 { | |||||
| opt.Methods = []string{ | |||||
| http.MethodGet, | |||||
| http.MethodHead, | |||||
| http.MethodPost, | |||||
| http.MethodPut, | |||||
| http.MethodPatch, | |||||
| http.MethodDelete, | |||||
| http.MethodOptions, | |||||
| } | |||||
| } | |||||
| } | |||||
| if opt.MaxAgeSeconds <= 0 { | |||||
| // cache options response for 600 secs | |||||
| // ref: https://stackoverflow.com/questions/54300997/is-it-possible-to-cache-http-options-response?noredirect=1#comment95790277_54300997 | |||||
| // ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age | |||||
| opt.MaxAgeSeconds = sec.Key("MAX_AGE_SECONDS").MustInt(600) | |||||
| } | |||||
| if !opt.AllowCredentials { | |||||
| opt.AllowCredentials = sec.Key("ALLOW_CREDENTIALS").MustBool(true) | |||||
| } | |||||
| return opt | |||||
| } | |||||
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin | |||||
| // https://fetch.spec.whatwg.org/#cors-protocol-and-credentials | |||||
| // For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource. | |||||
| func CORS(options ...Options) macaron.Handler { | |||||
| opt := prepareOptions(options) | |||||
| return func(ctx *macaron.Context, log *log.Logger) { | |||||
| reqOptions := ctx.Req.Method == http.MethodOptions | |||||
| headers := map[string]string{ | |||||
| "access-control-allow-methods": strings.Join(opt.Methods, ","), | |||||
| "access-control-allow-headers": ctx.Req.Header.Get("access-control-request-headers"), | |||||
| "access-control-max-age": strconv.Itoa(opt.MaxAgeSeconds), | |||||
| } | |||||
| if opt.AllowDomain == "*" { | |||||
| headers["access-control-allow-origin"] = "*" | |||||
| } else if opt.AllowDomain != "" { | |||||
| origin := ctx.Req.Header.Get("Origin") | |||||
| if reqOptions && origin == "" { | |||||
| respErrorf(ctx, log, http.StatusBadRequest, "missing origin header in CORS request") | |||||
| return | |||||
| } | |||||
| u, err := url.Parse(origin) | |||||
| if err != nil { | |||||
| respErrorf(ctx, log, http.StatusBadRequest, "Failed to parse CORS origin header. Reason: %v", err) | |||||
| return | |||||
| } | |||||
| ok := u.Hostname() == opt.AllowDomain || | |||||
| (opt.AllowSubdomain && strings.HasSuffix(u.Hostname(), "."+opt.AllowDomain)) | |||||
| if ok { | |||||
| u.Scheme = opt.Scheme | |||||
| headers["access-control-allow-origin"] = u.String() | |||||
| headers["access-control-allow-credentials"] = strconv.FormatBool(opt.AllowCredentials) | |||||
| headers["vary"] = "Origin" | |||||
| } | |||||
| if reqOptions && !ok { | |||||
| respErrorf(ctx, log, http.StatusBadRequest, "CORS request from prohibited domain %v", origin) | |||||
| return | |||||
| } | |||||
| } | |||||
| ctx.Resp.Before(func(w macaron.ResponseWriter) { | |||||
| for k, v := range headers { | |||||
| w.Header().Set(k, v) | |||||
| } | |||||
| }) | |||||
| if reqOptions { | |||||
| ctx.Status(200) // return response | |||||
| } | |||||
| } | |||||
| } | |||||
| func respErrorf(ctx *macaron.Context, log *log.Logger, statusCode int, format string, a ...interface{}) { | |||||
| msg := fmt.Sprintf(format, a...) | |||||
| log.Println(msg) | |||||
| ctx.WriteHeader(statusCode) | |||||
| _, err := ctx.Write([]byte(msg)) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| return | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| module github.com/go-macaron/cors | |||||
| go 1.12 | |||||
| require ( | |||||
| github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 // indirect | |||||
| github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect | |||||
| golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 // indirect | |||||
| gopkg.in/ini.v1 v1.42.0 // indirect | |||||
| gopkg.in/macaron.v1 v1.3.2 | |||||
| ) | |||||
| @@ -0,0 +1,19 @@ | |||||
| github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= | |||||
| github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= | |||||
| github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= | |||||
| github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= | |||||
| github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= | |||||
| github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||||
| github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= | |||||
| github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= | |||||
| github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||||
| github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= | |||||
| github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||||
| golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk= | |||||
| golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= | |||||
| golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||||
| gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= | |||||
| gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | |||||
| gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= | |||||
| gopkg.in/macaron.v1 v1.3.2/go.mod h1:PrsiawTWAGZs6wFbT5hlr7SQ2Ns9h7cUVtcUu4lQOVo= | |||||
| @@ -77,6 +77,10 @@ const ( | |||||
| 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. | ||||
| // | |||||
| // The following algorithms are supported: | |||||
| // RS256, ES256, ES384 and ES512. | |||||
| // See RFC7518 for more details about the algorithms. | |||||
| Key crypto.Signer | Key crypto.Signer | ||||
| // HTTPClient optionally specifies an HTTP client to use | // HTTPClient optionally specifies an HTTP client to use | ||||
| @@ -124,11 +128,7 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { | |||||
| return *c.dir, nil | return *c.dir, nil | ||||
| } | } | ||||
| dirURL := c.DirectoryURL | |||||
| if dirURL == "" { | |||||
| dirURL = LetsEncryptURL | |||||
| } | |||||
| res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK)) | |||||
| res, err := c.get(ctx, c.directoryURL(), wantStatus(http.StatusOK)) | |||||
| if err != nil { | if err != nil { | ||||
| return Directory{}, err | return Directory{}, err | ||||
| } | } | ||||
| @@ -161,6 +161,13 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { | |||||
| return *c.dir, nil | return *c.dir, nil | ||||
| } | } | ||||
| func (c *Client) directoryURL() string { | |||||
| if c.DirectoryURL != "" { | |||||
| return c.DirectoryURL | |||||
| } | |||||
| return LetsEncryptURL | |||||
| } | |||||
| // CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format. | // CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format. | ||||
| // The exp argument indicates the desired certificate validity duration. CA may issue a certificate | // The exp argument indicates the desired certificate validity duration. CA may issue a certificate | ||||
| // with a different duration. | // with a different duration. | ||||
| @@ -319,6 +326,20 @@ func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { | |||||
| // a valid authorization (Authorization.Status is StatusValid). If so, the caller | // a valid authorization (Authorization.Status is StatusValid). If so, the caller | ||||
| // need not fulfill any challenge and can proceed to requesting a certificate. | // need not fulfill any challenge and can proceed to requesting a certificate. | ||||
| func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { | func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { | ||||
| return c.authorize(ctx, "dns", domain) | |||||
| } | |||||
| // AuthorizeIP is the same as Authorize but requests IP address authorization. | |||||
| // Clients which successfully obtain such authorization may request to issue | |||||
| // a certificate for IP addresses. | |||||
| // | |||||
| // See the ACME spec extension for more details about IP address identifiers: | |||||
| // https://tools.ietf.org/html/draft-ietf-acme-ip. | |||||
| func (c *Client) AuthorizeIP(ctx context.Context, ipaddr string) (*Authorization, error) { | |||||
| return c.authorize(ctx, "ip", ipaddr) | |||||
| } | |||||
| func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization, error) { | |||||
| if _, err := c.Discover(ctx); err != nil { | if _, err := c.Discover(ctx); err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -332,7 +353,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, | |||||
| Identifier authzID `json:"identifier"` | Identifier authzID `json:"identifier"` | ||||
| }{ | }{ | ||||
| Resource: "new-authz", | Resource: "new-authz", | ||||
| Identifier: authzID{Type: "dns", Value: domain}, | |||||
| Identifier: authzID{Type: typ, Value: val}, | |||||
| } | } | ||||
| res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) | res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -693,12 +714,18 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun | |||||
| } | } | ||||
| // 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 the given URL. | |||||
| // or fetches a fresh one from a URL by issuing a HEAD request. | |||||
| // It first tries c.directoryURL() and then the provided url if the former fails. | |||||
| func (c *Client) popNonce(ctx context.Context, url string) (string, error) { | func (c *Client) popNonce(ctx context.Context, url string) (string, error) { | ||||
| c.noncesMu.Lock() | c.noncesMu.Lock() | ||||
| defer c.noncesMu.Unlock() | defer c.noncesMu.Unlock() | ||||
| if len(c.nonces) == 0 { | if len(c.nonces) == 0 { | ||||
| return c.fetchNonce(ctx, url) | |||||
| dirURL := c.directoryURL() | |||||
| v, err := c.fetchNonce(ctx, dirURL) | |||||
| if err != nil && url != dirURL { | |||||
| v, err = c.fetchNonce(ctx, url) | |||||
| } | |||||
| return v, err | |||||
| } | } | ||||
| var nonce string | var nonce string | ||||
| for nonce = range c.nonces { | for nonce = range c.nonces { | ||||
| @@ -69,7 +69,7 @@ func HostWhitelist(hosts ...string) HostPolicy { | |||||
| } | } | ||||
| return func(_ context.Context, host string) error { | return func(_ context.Context, host string) error { | ||||
| if !whitelist[host] { | if !whitelist[host] { | ||||
| return errors.New("acme/autocert: host not configured") | |||||
| return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host) | |||||
| } | } | ||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -25,7 +25,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byt | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| alg, sha := jwsHasher(key) | |||||
| alg, sha := jwsHasher(key.Public()) | |||||
| if alg == "" || !sha.Available() { | if alg == "" || !sha.Available() { | ||||
| return nil, ErrUnsupportedKey | return nil, ErrUnsupportedKey | ||||
| } | } | ||||
| @@ -97,13 +97,16 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { | |||||
| } | } | ||||
| // jwsSign signs the digest using the given key. | // jwsSign signs the digest using the given key. | ||||
| // It returns ErrUnsupportedKey if the key type is unknown. | |||||
| // The hash is used only for RSA keys. | |||||
| // The hash is unused for ECDSA keys. | |||||
| // | |||||
| // Note: non-stdlib crypto.Signer implementations are expected to return | |||||
| // the signature in the format as specified in RFC7518. | |||||
| // See https://tools.ietf.org/html/rfc7518 for more details. | |||||
| func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { | func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { | ||||
| switch key := key.(type) { | |||||
| case *rsa.PrivateKey: | |||||
| return key.Sign(rand.Reader, digest, hash) | |||||
| case *ecdsa.PrivateKey: | |||||
| if key, ok := key.(*ecdsa.PrivateKey); ok { | |||||
| // The key.Sign method of ecdsa returns ASN1-encoded signature. | |||||
| // So, we use the package Sign function instead | |||||
| // to get R and S values directly and format the result accordingly. | |||||
| r, s, err := ecdsa.Sign(rand.Reader, key, digest) | r, s, err := ecdsa.Sign(rand.Reader, key, digest) | ||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| @@ -118,18 +121,18 @@ func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) | |||||
| copy(sig[size*2-len(sb):], sb) | copy(sig[size*2-len(sb):], sb) | ||||
| return sig, nil | return sig, nil | ||||
| } | } | ||||
| return nil, ErrUnsupportedKey | |||||
| return key.Sign(rand.Reader, digest, hash) | |||||
| } | } | ||||
| // jwsHasher indicates suitable JWS algorithm name and a hash function | // jwsHasher indicates suitable JWS algorithm name and a hash function | ||||
| // to use for signing a digest with the provided key. | // to use for signing a digest with the provided key. | ||||
| // It returns ("", 0) if the key is not supported. | // It returns ("", 0) if the key is not supported. | ||||
| func jwsHasher(key crypto.Signer) (string, crypto.Hash) { | |||||
| switch key := key.(type) { | |||||
| case *rsa.PrivateKey: | |||||
| func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) { | |||||
| switch pub := pub.(type) { | |||||
| case *rsa.PublicKey: | |||||
| return "RS256", crypto.SHA256 | return "RS256", crypto.SHA256 | ||||
| case *ecdsa.PrivateKey: | |||||
| switch key.Params().Name { | |||||
| case *ecdsa.PublicKey: | |||||
| switch pub.Params().Name { | |||||
| case "P-256": | case "P-256": | ||||
| return "ES256", crypto.SHA256 | return "ES256", crypto.SHA256 | ||||
| case "P-384": | case "P-384": | ||||
| @@ -3,6 +3,14 @@ | |||||
| // license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
| // Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. | // Package blowfish implements Bruce Schneier's Blowfish encryption algorithm. | ||||
| // | |||||
| // Blowfish is a legacy cipher and its short block size makes it vulnerable to | |||||
| // birthday bound attacks (see https://sweet32.info). It should only be used | |||||
| // where compatibility with legacy systems, not security, is the goal. | |||||
| // | |||||
| // Deprecated: any new system should use AES (from crypto/aes, if necessary in | |||||
| // an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from | |||||
| // golang.org/x/crypto/chacha20poly1305). | |||||
| package blowfish // import "golang.org/x/crypto/blowfish" | package blowfish // import "golang.org/x/crypto/blowfish" | ||||
| // The code is a port of Bruce Schneier's C implementation. | // The code is a port of Bruce Schneier's C implementation. | ||||
| @@ -2,8 +2,15 @@ | |||||
| // 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. | ||||
| // Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common | |||||
| // OpenPGP cipher. | |||||
| // Package cast5 implements CAST5, as defined in RFC 2144. | |||||
| // | |||||
| // CAST5 is a legacy cipher and its short block size makes it vulnerable to | |||||
| // birthday bound attacks (see https://sweet32.info). It should only be used | |||||
| // where compatibility with legacy systems, not security, is the goal. | |||||
| // | |||||
| // Deprecated: any new system should use AES (from crypto/aes, if necessary in | |||||
| // an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from | |||||
| // golang.org/x/crypto/chacha20poly1305). | |||||
| package cast5 // import "golang.org/x/crypto/cast5" | package cast5 // import "golang.org/x/crypto/cast5" | ||||
| import "errors" | import "errors" | ||||
| @@ -86,7 +86,7 @@ func feFromBytes(dst *fieldElement, src *[32]byte) { | |||||
| h6 := load3(src[20:]) << 7 | h6 := load3(src[20:]) << 7 | ||||
| h7 := load3(src[23:]) << 5 | h7 := load3(src[23:]) << 5 | ||||
| h8 := load3(src[26:]) << 4 | h8 := load3(src[26:]) << 4 | ||||
| h9 := load3(src[29:]) << 2 | |||||
| h9 := (load3(src[29:]) & 0x7fffff) << 2 | |||||
| var carry [10]int64 | var carry [10]int64 | ||||
| carry[9] = (h9 + 1<<24) >> 25 | carry[9] = (h9 + 1<<24) >> 25 | ||||
| @@ -121,18 +121,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -236,18 +236,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -441,18 +441,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -591,18 +591,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -731,18 +731,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -846,18 +846,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -996,18 +996,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -1146,18 +1146,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -1332,18 +1332,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||||
| ADDQ AX,R12 | ADDQ AX,R12 | ||||
| ADCQ DX,R13 | ADCQ DX,R13 | ||||
| MOVQ $REDMASK51,DX | MOVQ $REDMASK51,DX | ||||
| SHLQ $13,CX:SI | |||||
| SHLQ $13,SI,CX | |||||
| ANDQ DX,SI | ANDQ DX,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ DX,R8 | ANDQ DX,R8 | ||||
| ADDQ CX,R8 | ADDQ CX,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ DX,R10 | ANDQ DX,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ DX,R12 | ANDQ DX,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ DX,R14 | ANDQ DX,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| IMUL3Q $19,R15,CX | IMUL3Q $19,R15,CX | ||||
| @@ -124,18 +124,18 @@ TEXT ·mul(SB),0,$16-24 | |||||
| ADDQ AX,R14 | ADDQ AX,R14 | ||||
| ADCQ DX,R15 | ADCQ DX,R15 | ||||
| MOVQ $REDMASK51,SI | MOVQ $REDMASK51,SI | ||||
| SHLQ $13,R9:R8 | |||||
| SHLQ $13,R8,R9 | |||||
| ANDQ SI,R8 | ANDQ SI,R8 | ||||
| SHLQ $13,R11:R10 | |||||
| SHLQ $13,R10,R11 | |||||
| ANDQ SI,R10 | ANDQ SI,R10 | ||||
| ADDQ R9,R10 | ADDQ R9,R10 | ||||
| SHLQ $13,R13:R12 | |||||
| SHLQ $13,R12,R13 | |||||
| ANDQ SI,R12 | ANDQ SI,R12 | ||||
| ADDQ R11,R12 | ADDQ R11,R12 | ||||
| SHLQ $13,R15:R14 | |||||
| SHLQ $13,R14,R15 | |||||
| ANDQ SI,R14 | ANDQ SI,R14 | ||||
| ADDQ R13,R14 | ADDQ R13,R14 | ||||
| SHLQ $13,BP:BX | |||||
| SHLQ $13,BX,BP | |||||
| ANDQ SI,BX | ANDQ SI,BX | ||||
| ADDQ R15,BX | ADDQ R15,BX | ||||
| IMUL3Q $19,BP,DX | IMUL3Q $19,BP,DX | ||||
| @@ -87,18 +87,18 @@ TEXT ·square(SB),7,$0-16 | |||||
| ADDQ AX,R13 | ADDQ AX,R13 | ||||
| ADCQ DX,R14 | ADCQ DX,R14 | ||||
| MOVQ $REDMASK51,SI | MOVQ $REDMASK51,SI | ||||
| SHLQ $13,R8:CX | |||||
| SHLQ $13,CX,R8 | |||||
| ANDQ SI,CX | ANDQ SI,CX | ||||
| SHLQ $13,R10:R9 | |||||
| SHLQ $13,R9,R10 | |||||
| ANDQ SI,R9 | ANDQ SI,R9 | ||||
| ADDQ R8,R9 | ADDQ R8,R9 | ||||
| SHLQ $13,R12:R11 | |||||
| SHLQ $13,R11,R12 | |||||
| ANDQ SI,R11 | ANDQ SI,R11 | ||||
| ADDQ R10,R11 | ADDQ R10,R11 | ||||
| SHLQ $13,R14:R13 | |||||
| SHLQ $13,R13,R14 | |||||
| ANDQ SI,R13 | ANDQ SI,R13 | ||||
| ADDQ R12,R13 | ADDQ R12,R13 | ||||
| SHLQ $13,BX:R15 | |||||
| SHLQ $13,R15,BX | |||||
| ANDQ SI,R15 | ANDQ SI,R15 | ||||
| ADDQ R14,R15 | ADDQ R14,R15 | ||||
| IMUL3Q $19,BX,DX | IMUL3Q $19,BX,DX | ||||
| @@ -0,0 +1,308 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build go1.11 | |||||
| // +build !gccgo,!appengine | |||||
| #include "textflag.h" | |||||
| #define NUM_ROUNDS 10 | |||||
| // func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) | |||||
| TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 | |||||
| MOVD dst+0(FP), R1 | |||||
| MOVD src+24(FP), R2 | |||||
| MOVD src_len+32(FP), R3 | |||||
| MOVD key+48(FP), R4 | |||||
| MOVD nonce+56(FP), R6 | |||||
| MOVD counter+64(FP), R7 | |||||
| MOVD $·constants(SB), R10 | |||||
| MOVD $·incRotMatrix(SB), R11 | |||||
| MOVW (R7), R20 | |||||
| AND $~255, R3, R13 | |||||
| ADD R2, R13, R12 // R12 for block end | |||||
| AND $255, R3, R13 | |||||
| loop: | |||||
| MOVD $NUM_ROUNDS, R21 | |||||
| VLD1 (R11), [V30.S4, V31.S4] | |||||
| // load contants | |||||
| // VLD4R (R10), [V0.S4, V1.S4, V2.S4, V3.S4] | |||||
| WORD $0x4D60E940 | |||||
| // load keys | |||||
| // VLD4R 16(R4), [V4.S4, V5.S4, V6.S4, V7.S4] | |||||
| WORD $0x4DFFE884 | |||||
| // VLD4R 16(R4), [V8.S4, V9.S4, V10.S4, V11.S4] | |||||
| WORD $0x4DFFE888 | |||||
| SUB $32, R4 | |||||
| // load counter + nonce | |||||
| // VLD1R (R7), [V12.S4] | |||||
| WORD $0x4D40C8EC | |||||
| // VLD3R (R6), [V13.S4, V14.S4, V15.S4] | |||||
| WORD $0x4D40E8CD | |||||
| // update counter | |||||
| VADD V30.S4, V12.S4, V12.S4 | |||||
| chacha: | |||||
| // V0..V3 += V4..V7 | |||||
| // V12..V15 <<<= ((V12..V15 XOR V0..V3), 16) | |||||
| VADD V0.S4, V4.S4, V0.S4 | |||||
| VADD V1.S4, V5.S4, V1.S4 | |||||
| VADD V2.S4, V6.S4, V2.S4 | |||||
| VADD V3.S4, V7.S4, V3.S4 | |||||
| VEOR V12.B16, V0.B16, V12.B16 | |||||
| VEOR V13.B16, V1.B16, V13.B16 | |||||
| VEOR V14.B16, V2.B16, V14.B16 | |||||
| VEOR V15.B16, V3.B16, V15.B16 | |||||
| VREV32 V12.H8, V12.H8 | |||||
| VREV32 V13.H8, V13.H8 | |||||
| VREV32 V14.H8, V14.H8 | |||||
| VREV32 V15.H8, V15.H8 | |||||
| // V8..V11 += V12..V15 | |||||
| // V4..V7 <<<= ((V4..V7 XOR V8..V11), 12) | |||||
| VADD V8.S4, V12.S4, V8.S4 | |||||
| VADD V9.S4, V13.S4, V9.S4 | |||||
| VADD V10.S4, V14.S4, V10.S4 | |||||
| VADD V11.S4, V15.S4, V11.S4 | |||||
| VEOR V8.B16, V4.B16, V16.B16 | |||||
| VEOR V9.B16, V5.B16, V17.B16 | |||||
| VEOR V10.B16, V6.B16, V18.B16 | |||||
| VEOR V11.B16, V7.B16, V19.B16 | |||||
| VSHL $12, V16.S4, V4.S4 | |||||
| VSHL $12, V17.S4, V5.S4 | |||||
| VSHL $12, V18.S4, V6.S4 | |||||
| VSHL $12, V19.S4, V7.S4 | |||||
| VSRI $20, V16.S4, V4.S4 | |||||
| VSRI $20, V17.S4, V5.S4 | |||||
| VSRI $20, V18.S4, V6.S4 | |||||
| VSRI $20, V19.S4, V7.S4 | |||||
| // V0..V3 += V4..V7 | |||||
| // V12..V15 <<<= ((V12..V15 XOR V0..V3), 8) | |||||
| VADD V0.S4, V4.S4, V0.S4 | |||||
| VADD V1.S4, V5.S4, V1.S4 | |||||
| VADD V2.S4, V6.S4, V2.S4 | |||||
| VADD V3.S4, V7.S4, V3.S4 | |||||
| VEOR V12.B16, V0.B16, V12.B16 | |||||
| VEOR V13.B16, V1.B16, V13.B16 | |||||
| VEOR V14.B16, V2.B16, V14.B16 | |||||
| VEOR V15.B16, V3.B16, V15.B16 | |||||
| VTBL V31.B16, [V12.B16], V12.B16 | |||||
| VTBL V31.B16, [V13.B16], V13.B16 | |||||
| VTBL V31.B16, [V14.B16], V14.B16 | |||||
| VTBL V31.B16, [V15.B16], V15.B16 | |||||
| // V8..V11 += V12..V15 | |||||
| // V4..V7 <<<= ((V4..V7 XOR V8..V11), 7) | |||||
| VADD V12.S4, V8.S4, V8.S4 | |||||
| VADD V13.S4, V9.S4, V9.S4 | |||||
| VADD V14.S4, V10.S4, V10.S4 | |||||
| VADD V15.S4, V11.S4, V11.S4 | |||||
| VEOR V8.B16, V4.B16, V16.B16 | |||||
| VEOR V9.B16, V5.B16, V17.B16 | |||||
| VEOR V10.B16, V6.B16, V18.B16 | |||||
| VEOR V11.B16, V7.B16, V19.B16 | |||||
| VSHL $7, V16.S4, V4.S4 | |||||
| VSHL $7, V17.S4, V5.S4 | |||||
| VSHL $7, V18.S4, V6.S4 | |||||
| VSHL $7, V19.S4, V7.S4 | |||||
| VSRI $25, V16.S4, V4.S4 | |||||
| VSRI $25, V17.S4, V5.S4 | |||||
| VSRI $25, V18.S4, V6.S4 | |||||
| VSRI $25, V19.S4, V7.S4 | |||||
| // V0..V3 += V5..V7, V4 | |||||
| // V15,V12-V14 <<<= ((V15,V12-V14 XOR V0..V3), 16) | |||||
| VADD V0.S4, V5.S4, V0.S4 | |||||
| VADD V1.S4, V6.S4, V1.S4 | |||||
| VADD V2.S4, V7.S4, V2.S4 | |||||
| VADD V3.S4, V4.S4, V3.S4 | |||||
| VEOR V15.B16, V0.B16, V15.B16 | |||||
| VEOR V12.B16, V1.B16, V12.B16 | |||||
| VEOR V13.B16, V2.B16, V13.B16 | |||||
| VEOR V14.B16, V3.B16, V14.B16 | |||||
| VREV32 V12.H8, V12.H8 | |||||
| VREV32 V13.H8, V13.H8 | |||||
| VREV32 V14.H8, V14.H8 | |||||
| VREV32 V15.H8, V15.H8 | |||||
| // V10 += V15; V5 <<<= ((V10 XOR V5), 12) | |||||
| // ... | |||||
| VADD V15.S4, V10.S4, V10.S4 | |||||
| VADD V12.S4, V11.S4, V11.S4 | |||||
| VADD V13.S4, V8.S4, V8.S4 | |||||
| VADD V14.S4, V9.S4, V9.S4 | |||||
| VEOR V10.B16, V5.B16, V16.B16 | |||||
| VEOR V11.B16, V6.B16, V17.B16 | |||||
| VEOR V8.B16, V7.B16, V18.B16 | |||||
| VEOR V9.B16, V4.B16, V19.B16 | |||||
| VSHL $12, V16.S4, V5.S4 | |||||
| VSHL $12, V17.S4, V6.S4 | |||||
| VSHL $12, V18.S4, V7.S4 | |||||
| VSHL $12, V19.S4, V4.S4 | |||||
| VSRI $20, V16.S4, V5.S4 | |||||
| VSRI $20, V17.S4, V6.S4 | |||||
| VSRI $20, V18.S4, V7.S4 | |||||
| VSRI $20, V19.S4, V4.S4 | |||||
| // V0 += V5; V15 <<<= ((V0 XOR V15), 8) | |||||
| // ... | |||||
| VADD V5.S4, V0.S4, V0.S4 | |||||
| VADD V6.S4, V1.S4, V1.S4 | |||||
| VADD V7.S4, V2.S4, V2.S4 | |||||
| VADD V4.S4, V3.S4, V3.S4 | |||||
| VEOR V0.B16, V15.B16, V15.B16 | |||||
| VEOR V1.B16, V12.B16, V12.B16 | |||||
| VEOR V2.B16, V13.B16, V13.B16 | |||||
| VEOR V3.B16, V14.B16, V14.B16 | |||||
| VTBL V31.B16, [V12.B16], V12.B16 | |||||
| VTBL V31.B16, [V13.B16], V13.B16 | |||||
| VTBL V31.B16, [V14.B16], V14.B16 | |||||
| VTBL V31.B16, [V15.B16], V15.B16 | |||||
| // V10 += V15; V5 <<<= ((V10 XOR V5), 7) | |||||
| // ... | |||||
| VADD V15.S4, V10.S4, V10.S4 | |||||
| VADD V12.S4, V11.S4, V11.S4 | |||||
| VADD V13.S4, V8.S4, V8.S4 | |||||
| VADD V14.S4, V9.S4, V9.S4 | |||||
| VEOR V10.B16, V5.B16, V16.B16 | |||||
| VEOR V11.B16, V6.B16, V17.B16 | |||||
| VEOR V8.B16, V7.B16, V18.B16 | |||||
| VEOR V9.B16, V4.B16, V19.B16 | |||||
| VSHL $7, V16.S4, V5.S4 | |||||
| VSHL $7, V17.S4, V6.S4 | |||||
| VSHL $7, V18.S4, V7.S4 | |||||
| VSHL $7, V19.S4, V4.S4 | |||||
| VSRI $25, V16.S4, V5.S4 | |||||
| VSRI $25, V17.S4, V6.S4 | |||||
| VSRI $25, V18.S4, V7.S4 | |||||
| VSRI $25, V19.S4, V4.S4 | |||||
| SUB $1, R21 | |||||
| CBNZ R21, chacha | |||||
| // VLD4R (R10), [V16.S4, V17.S4, V18.S4, V19.S4] | |||||
| WORD $0x4D60E950 | |||||
| // VLD4R 16(R4), [V20.S4, V21.S4, V22.S4, V23.S4] | |||||
| WORD $0x4DFFE894 | |||||
| VADD V30.S4, V12.S4, V12.S4 | |||||
| VADD V16.S4, V0.S4, V0.S4 | |||||
| VADD V17.S4, V1.S4, V1.S4 | |||||
| VADD V18.S4, V2.S4, V2.S4 | |||||
| VADD V19.S4, V3.S4, V3.S4 | |||||
| // VLD4R 16(R4), [V24.S4, V25.S4, V26.S4, V27.S4] | |||||
| WORD $0x4DFFE898 | |||||
| // restore R4 | |||||
| SUB $32, R4 | |||||
| // load counter + nonce | |||||
| // VLD1R (R7), [V28.S4] | |||||
| WORD $0x4D40C8FC | |||||
| // VLD3R (R6), [V29.S4, V30.S4, V31.S4] | |||||
| WORD $0x4D40E8DD | |||||
| VADD V20.S4, V4.S4, V4.S4 | |||||
| VADD V21.S4, V5.S4, V5.S4 | |||||
| VADD V22.S4, V6.S4, V6.S4 | |||||
| VADD V23.S4, V7.S4, V7.S4 | |||||
| VADD V24.S4, V8.S4, V8.S4 | |||||
| VADD V25.S4, V9.S4, V9.S4 | |||||
| VADD V26.S4, V10.S4, V10.S4 | |||||
| VADD V27.S4, V11.S4, V11.S4 | |||||
| VADD V28.S4, V12.S4, V12.S4 | |||||
| VADD V29.S4, V13.S4, V13.S4 | |||||
| VADD V30.S4, V14.S4, V14.S4 | |||||
| VADD V31.S4, V15.S4, V15.S4 | |||||
| VZIP1 V1.S4, V0.S4, V16.S4 | |||||
| VZIP2 V1.S4, V0.S4, V17.S4 | |||||
| VZIP1 V3.S4, V2.S4, V18.S4 | |||||
| VZIP2 V3.S4, V2.S4, V19.S4 | |||||
| VZIP1 V5.S4, V4.S4, V20.S4 | |||||
| VZIP2 V5.S4, V4.S4, V21.S4 | |||||
| VZIP1 V7.S4, V6.S4, V22.S4 | |||||
| VZIP2 V7.S4, V6.S4, V23.S4 | |||||
| VZIP1 V9.S4, V8.S4, V24.S4 | |||||
| VZIP2 V9.S4, V8.S4, V25.S4 | |||||
| VZIP1 V11.S4, V10.S4, V26.S4 | |||||
| VZIP2 V11.S4, V10.S4, V27.S4 | |||||
| VZIP1 V13.S4, V12.S4, V28.S4 | |||||
| VZIP2 V13.S4, V12.S4, V29.S4 | |||||
| VZIP1 V15.S4, V14.S4, V30.S4 | |||||
| VZIP2 V15.S4, V14.S4, V31.S4 | |||||
| VZIP1 V18.D2, V16.D2, V0.D2 | |||||
| VZIP2 V18.D2, V16.D2, V4.D2 | |||||
| VZIP1 V19.D2, V17.D2, V8.D2 | |||||
| VZIP2 V19.D2, V17.D2, V12.D2 | |||||
| VLD1.P 64(R2), [V16.B16, V17.B16, V18.B16, V19.B16] | |||||
| VZIP1 V22.D2, V20.D2, V1.D2 | |||||
| VZIP2 V22.D2, V20.D2, V5.D2 | |||||
| VZIP1 V23.D2, V21.D2, V9.D2 | |||||
| VZIP2 V23.D2, V21.D2, V13.D2 | |||||
| VLD1.P 64(R2), [V20.B16, V21.B16, V22.B16, V23.B16] | |||||
| VZIP1 V26.D2, V24.D2, V2.D2 | |||||
| VZIP2 V26.D2, V24.D2, V6.D2 | |||||
| VZIP1 V27.D2, V25.D2, V10.D2 | |||||
| VZIP2 V27.D2, V25.D2, V14.D2 | |||||
| VLD1.P 64(R2), [V24.B16, V25.B16, V26.B16, V27.B16] | |||||
| VZIP1 V30.D2, V28.D2, V3.D2 | |||||
| VZIP2 V30.D2, V28.D2, V7.D2 | |||||
| VZIP1 V31.D2, V29.D2, V11.D2 | |||||
| VZIP2 V31.D2, V29.D2, V15.D2 | |||||
| VLD1.P 64(R2), [V28.B16, V29.B16, V30.B16, V31.B16] | |||||
| VEOR V0.B16, V16.B16, V16.B16 | |||||
| VEOR V1.B16, V17.B16, V17.B16 | |||||
| VEOR V2.B16, V18.B16, V18.B16 | |||||
| VEOR V3.B16, V19.B16, V19.B16 | |||||
| VST1.P [V16.B16, V17.B16, V18.B16, V19.B16], 64(R1) | |||||
| VEOR V4.B16, V20.B16, V20.B16 | |||||
| VEOR V5.B16, V21.B16, V21.B16 | |||||
| VEOR V6.B16, V22.B16, V22.B16 | |||||
| VEOR V7.B16, V23.B16, V23.B16 | |||||
| VST1.P [V20.B16, V21.B16, V22.B16, V23.B16], 64(R1) | |||||
| VEOR V8.B16, V24.B16, V24.B16 | |||||
| VEOR V9.B16, V25.B16, V25.B16 | |||||
| VEOR V10.B16, V26.B16, V26.B16 | |||||
| VEOR V11.B16, V27.B16, V27.B16 | |||||
| VST1.P [V24.B16, V25.B16, V26.B16, V27.B16], 64(R1) | |||||
| VEOR V12.B16, V28.B16, V28.B16 | |||||
| VEOR V13.B16, V29.B16, V29.B16 | |||||
| VEOR V14.B16, V30.B16, V30.B16 | |||||
| VEOR V15.B16, V31.B16, V31.B16 | |||||
| VST1.P [V28.B16, V29.B16, V30.B16, V31.B16], 64(R1) | |||||
| ADD $4, R20 | |||||
| MOVW R20, (R7) // update counter | |||||
| CMP R2, R12 | |||||
| BGT loop | |||||
| RET | |||||
| DATA ·constants+0x00(SB)/4, $0x61707865 | |||||
| DATA ·constants+0x04(SB)/4, $0x3320646e | |||||
| DATA ·constants+0x08(SB)/4, $0x79622d32 | |||||
| DATA ·constants+0x0c(SB)/4, $0x6b206574 | |||||
| GLOBL ·constants(SB), NOPTR|RODATA, $32 | |||||
| DATA ·incRotMatrix+0x00(SB)/4, $0x00000000 | |||||
| DATA ·incRotMatrix+0x04(SB)/4, $0x00000001 | |||||
| DATA ·incRotMatrix+0x08(SB)/4, $0x00000002 | |||||
| DATA ·incRotMatrix+0x0c(SB)/4, $0x00000003 | |||||
| DATA ·incRotMatrix+0x10(SB)/4, $0x02010003 | |||||
| DATA ·incRotMatrix+0x14(SB)/4, $0x06050407 | |||||
| DATA ·incRotMatrix+0x18(SB)/4, $0x0A09080B | |||||
| DATA ·incRotMatrix+0x1c(SB)/4, $0x0E0D0C0F | |||||
| GLOBL ·incRotMatrix(SB), NOPTR|RODATA, $32 | |||||
| @@ -0,0 +1,31 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build go1.11 | |||||
| // +build !gccgo | |||||
| package chacha20 | |||||
| const ( | |||||
| haveAsm = true | |||||
| bufSize = 256 | |||||
| ) | |||||
| //go:noescape | |||||
| func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32) | |||||
| func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { | |||||
| if len(src) >= bufSize { | |||||
| xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter) | |||||
| } | |||||
| if len(src)%bufSize != 0 { | |||||
| i := len(src) - len(src)%bufSize | |||||
| c.buf = [bufSize]byte{} | |||||
| copy(c.buf[:], src[i:]) | |||||
| xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter) | |||||
| c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize]) | |||||
| } | |||||
| } | |||||
| @@ -2,7 +2,7 @@ | |||||
| // 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. | ||||
| // +build !s390x gccgo appengine | |||||
| // +build !arm64,!s390x arm64,!go1.11 gccgo appengine | |||||
| package chacha20 | package chacha20 | ||||
| @@ -6,14 +6,13 @@ | |||||
| package chacha20 | package chacha20 | ||||
| var haveAsm = hasVectorFacility() | |||||
| import ( | |||||
| "golang.org/x/sys/cpu" | |||||
| ) | |||||
| const bufSize = 256 | |||||
| var haveAsm = cpu.S390X.HasVX | |||||
| // hasVectorFacility reports whether the machine supports the vector | |||||
| // facility (vx). | |||||
| // Implementation in asm_s390x.s. | |||||
| func hasVectorFacility() bool | |||||
| 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. | // be called when the vector facility is available. | ||||
| @@ -258,26 +258,3 @@ tail: | |||||
| MOVD R8, R3 | MOVD R8, R3 | ||||
| MOVD $0, R4 | MOVD $0, R4 | ||||
| JMP continue | JMP continue | ||||
| // func hasVectorFacility() bool | |||||
| TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 | |||||
| MOVD $x-24(SP), R1 | |||||
| XC $24, 0(R1), 0(R1) // clear the storage | |||||
| MOVD $2, R0 // R0 is the number of double words stored -1 | |||||
| WORD $0xB2B01000 // STFLE 0(R1) | |||||
| XOR R0, R0 // reset the value of R0 | |||||
| MOVBZ z-8(SP), R1 | |||||
| AND $0x40, R1 | |||||
| BEQ novector | |||||
| vectorinstalled: | |||||
| // check if the vector instruction has been enabled | |||||
| VLEIB $0, $0xF, V16 | |||||
| VLGVB $0, V16, R1 | |||||
| CMPBNE R1, $0xF, novector | |||||
| MOVB $1, ret+0(FP) // have vx | |||||
| RET | |||||
| novector: | |||||
| MOVB $0, ret+0(FP) // no vx | |||||
| RET | |||||
| @@ -3,6 +3,10 @@ | |||||
| // license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
| // Package md4 implements the MD4 hash algorithm as defined in RFC 1320. | // Package md4 implements the MD4 hash algorithm as defined in RFC 1320. | ||||
| // | |||||
| // Deprecated: MD4 is cryptographically broken and should should only be used | |||||
| // where compatibility with legacy systems, not security, is the goal. Instead, | |||||
| // use a secure hash like SHA-256 (from crypto/sha256). | |||||
| package md4 // import "golang.org/x/crypto/md4" | package md4 // import "golang.org/x/crypto/md4" | ||||
| import ( | import ( | ||||
| @@ -333,7 +333,6 @@ func ReadEntity(packets *packet.Reader) (*Entity, error) { | |||||
| return nil, errors.StructuralError("primary key cannot be used for signatures") | return nil, errors.StructuralError("primary key cannot be used for signatures") | ||||
| } | } | ||||
| var current *Identity | |||||
| var revocations []*packet.Signature | var revocations []*packet.Signature | ||||
| EachPacket: | EachPacket: | ||||
| for { | for { | ||||
| @@ -346,36 +345,8 @@ EachPacket: | |||||
| switch pkt := p.(type) { | switch pkt := p.(type) { | ||||
| case *packet.UserId: | case *packet.UserId: | ||||
| // Make a new Identity object, that we might wind up throwing away. | |||||
| // We'll only add it if we get a valid self-signature over this | |||||
| // userID. | |||||
| current = new(Identity) | |||||
| current.Name = pkt.Id | |||||
| current.UserId = pkt | |||||
| for { | |||||
| p, err = packets.Next() | |||||
| if err == io.EOF { | |||||
| break EachPacket | |||||
| } else if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| sig, ok := p.(*packet.Signature) | |||||
| if !ok { | |||||
| packets.Unread(p) | |||||
| continue EachPacket | |||||
| } | |||||
| if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { | |||||
| if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { | |||||
| return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error()) | |||||
| } | |||||
| current.SelfSignature = sig | |||||
| e.Identities[pkt.Id] = current | |||||
| } else { | |||||
| current.Signatures = append(current.Signatures, sig) | |||||
| } | |||||
| if err := addUserID(e, packets, pkt); err != nil { | |||||
| return nil, err | |||||
| } | } | ||||
| case *packet.Signature: | case *packet.Signature: | ||||
| if pkt.SigType == packet.SigTypeKeyRevocation { | if pkt.SigType == packet.SigTypeKeyRevocation { | ||||
| @@ -384,11 +355,9 @@ EachPacket: | |||||
| // TODO: RFC4880 5.2.1 permits signatures | // TODO: RFC4880 5.2.1 permits signatures | ||||
| // directly on keys (eg. to bind additional | // directly on keys (eg. to bind additional | ||||
| // revocation keys). | // revocation keys). | ||||
| } else if current == nil { | |||||
| return nil, errors.StructuralError("signature packet found before user id packet") | |||||
| } else { | |||||
| current.Signatures = append(current.Signatures, pkt) | |||||
| } | } | ||||
| // Else, ignoring the signature as it does not follow anything | |||||
| // we would know to attach it to. | |||||
| case *packet.PrivateKey: | case *packet.PrivateKey: | ||||
| if pkt.IsSubkey == false { | if pkt.IsSubkey == false { | ||||
| packets.Unread(p) | packets.Unread(p) | ||||
| @@ -429,33 +398,105 @@ EachPacket: | |||||
| return e, nil | return e, nil | ||||
| } | } | ||||
| func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { | |||||
| // Make a new Identity object, that we might wind up throwing away. | |||||
| // We'll only add it if we get a valid self-signature over this | |||||
| // userID. | |||||
| identity := new(Identity) | |||||
| identity.Name = pkt.Id | |||||
| identity.UserId = pkt | |||||
| for { | |||||
| p, err := packets.Next() | |||||
| if err == io.EOF { | |||||
| break | |||||
| } else if err != nil { | |||||
| return err | |||||
| } | |||||
| sig, ok := p.(*packet.Signature) | |||||
| if !ok { | |||||
| packets.Unread(p) | |||||
| break | |||||
| } | |||||
| if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { | |||||
| if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { | |||||
| return errors.StructuralError("user ID self-signature invalid: " + err.Error()) | |||||
| } | |||||
| identity.SelfSignature = sig | |||||
| e.Identities[pkt.Id] = identity | |||||
| } else { | |||||
| identity.Signatures = append(identity.Signatures, sig) | |||||
| } | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { | func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { | ||||
| var subKey Subkey | var subKey Subkey | ||||
| subKey.PublicKey = pub | subKey.PublicKey = pub | ||||
| subKey.PrivateKey = priv | subKey.PrivateKey = priv | ||||
| p, err := packets.Next() | |||||
| if err == io.EOF { | |||||
| return io.ErrUnexpectedEOF | |||||
| } | |||||
| if err != nil { | |||||
| return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||||
| for { | |||||
| p, err := packets.Next() | |||||
| if err == io.EOF { | |||||
| break | |||||
| } else if err != nil { | |||||
| return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||||
| } | |||||
| sig, ok := p.(*packet.Signature) | |||||
| if !ok { | |||||
| packets.Unread(p) | |||||
| break | |||||
| } | |||||
| if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation { | |||||
| return errors.StructuralError("subkey signature with wrong type") | |||||
| } | |||||
| if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil { | |||||
| return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||||
| } | |||||
| switch sig.SigType { | |||||
| case packet.SigTypeSubkeyRevocation: | |||||
| subKey.Sig = sig | |||||
| case packet.SigTypeSubkeyBinding: | |||||
| if shouldReplaceSubkeySig(subKey.Sig, sig) { | |||||
| subKey.Sig = sig | |||||
| } | |||||
| } | |||||
| } | } | ||||
| var ok bool | |||||
| subKey.Sig, ok = p.(*packet.Signature) | |||||
| if !ok { | |||||
| if subKey.Sig == nil { | |||||
| return errors.StructuralError("subkey packet not followed by signature") | return errors.StructuralError("subkey packet not followed by signature") | ||||
| } | } | ||||
| if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation { | |||||
| return errors.StructuralError("subkey signature with wrong type") | |||||
| } | |||||
| err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig) | |||||
| if err != nil { | |||||
| return errors.StructuralError("subkey signature invalid: " + err.Error()) | |||||
| } | |||||
| e.Subkeys = append(e.Subkeys, subKey) | e.Subkeys = append(e.Subkeys, subKey) | ||||
| return nil | return nil | ||||
| } | } | ||||
| func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { | |||||
| if potentialNewSig == nil { | |||||
| return false | |||||
| } | |||||
| if existingSig == nil { | |||||
| return true | |||||
| } | |||||
| if existingSig.SigType == packet.SigTypeSubkeyRevocation { | |||||
| return false // never override a revocation signature | |||||
| } | |||||
| return potentialNewSig.CreationTime.After(existingSig.CreationTime) | |||||
| } | |||||
| const defaultRSAKeyBits = 2048 | const defaultRSAKeyBits = 2048 | ||||
| // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a | // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a | ||||
| @@ -404,14 +404,16 @@ const ( | |||||
| type PublicKeyAlgorithm uint8 | type PublicKeyAlgorithm uint8 | ||||
| const ( | const ( | ||||
| PubKeyAlgoRSA PublicKeyAlgorithm = 1 | |||||
| PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 | |||||
| PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 | |||||
| PubKeyAlgoElGamal PublicKeyAlgorithm = 16 | |||||
| PubKeyAlgoDSA PublicKeyAlgorithm = 17 | |||||
| PubKeyAlgoRSA PublicKeyAlgorithm = 1 | |||||
| PubKeyAlgoElGamal PublicKeyAlgorithm = 16 | |||||
| PubKeyAlgoDSA PublicKeyAlgorithm = 17 | |||||
| // RFC 6637, Section 5. | // RFC 6637, Section 5. | ||||
| PubKeyAlgoECDH PublicKeyAlgorithm = 18 | PubKeyAlgoECDH PublicKeyAlgorithm = 18 | ||||
| PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | PubKeyAlgoECDSA PublicKeyAlgorithm = 19 | ||||
| // Deprecated in RFC 4880, Section 13.5. Use key flags instead. | |||||
| PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 | |||||
| PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 | |||||
| ) | ) | ||||
| // CanEncrypt returns true if it's possible to encrypt a message to a public | // CanEncrypt returns true if it's possible to encrypt a message to a public | ||||
| @@ -64,14 +64,19 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK | |||||
| return pk | return pk | ||||
| } | } | ||||
| // NewSignerPrivateKey creates a sign-only PrivateKey from a crypto.Signer that | |||||
| // NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that | |||||
| // implements RSA or ECDSA. | // implements RSA or ECDSA. | ||||
| func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { | func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { | ||||
| pk := new(PrivateKey) | pk := new(PrivateKey) | ||||
| // In general, the public Keys should be used as pointers. We still | |||||
| // type-switch on the values, for backwards-compatibility. | |||||
| switch pubkey := signer.Public().(type) { | switch pubkey := signer.Public().(type) { | ||||
| case *rsa.PublicKey: | |||||
| pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) | |||||
| case rsa.PublicKey: | case rsa.PublicKey: | ||||
| pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) | pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) | ||||
| pk.PubKeyAlgo = PubKeyAlgoRSASignOnly | |||||
| case *ecdsa.PublicKey: | |||||
| pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) | |||||
| case ecdsa.PublicKey: | case ecdsa.PublicKey: | ||||
| pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) | pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) | ||||
| default: | default: | ||||
| @@ -542,7 +542,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e | |||||
| r, s, err = ecdsa.Sign(config.Random(), pk, digest) | r, s, err = ecdsa.Sign(config.Random(), pk, digest) | ||||
| } else { | } else { | ||||
| var b []byte | var b []byte | ||||
| b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, nil) | |||||
| b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) | |||||
| if err == nil { | if err == nil { | ||||
| r, s, err = unwrapECDSASig(b) | r, s, err = unwrapECDSASig(b) | ||||
| } | } | ||||
| @@ -80,7 +80,7 @@ func (uat *UserAttribute) Serialize(w io.Writer) (err error) { | |||||
| // ImageData returns zero or more byte slices, each containing | // ImageData returns zero or more byte slices, each containing | ||||
| // JPEG File Interchange Format (JFIF), for each photo in the | // JPEG File Interchange Format (JFIF), for each photo in the | ||||
| // the user attribute packet. | |||||
| // user attribute packet. | |||||
| func (uat *UserAttribute) ImageData() (imageData [][]byte) { | func (uat *UserAttribute) ImageData() (imageData [][]byte) { | ||||
| for _, sp := range uat.Contents { | for _, sp := range uat.Contents { | ||||
| if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { | if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { | ||||
| @@ -271,6 +271,7 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint | |||||
| // These are the possible hash functions that we'll use for the signature. | // These are the possible hash functions that we'll use for the signature. | ||||
| candidateHashes := []uint8{ | candidateHashes := []uint8{ | ||||
| hashToHashId(crypto.SHA256), | hashToHashId(crypto.SHA256), | ||||
| hashToHashId(crypto.SHA384), | |||||
| hashToHashId(crypto.SHA512), | hashToHashId(crypto.SHA512), | ||||
| hashToHashId(crypto.SHA1), | hashToHashId(crypto.SHA1), | ||||
| hashToHashId(crypto.RIPEMD160), | hashToHashId(crypto.RIPEMD160), | ||||
| @@ -349,6 +350,7 @@ func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Con | |||||
| // These are the possible hash functions that we'll use for the signature. | // These are the possible hash functions that we'll use for the signature. | ||||
| candidateHashes := []uint8{ | candidateHashes := []uint8{ | ||||
| hashToHashId(crypto.SHA256), | hashToHashId(crypto.SHA256), | ||||
| hashToHashId(crypto.SHA384), | |||||
| hashToHashId(crypto.SHA512), | hashToHashId(crypto.SHA512), | ||||
| hashToHashId(crypto.SHA1), | hashToHashId(crypto.SHA1), | ||||
| hashToHashId(crypto.RIPEMD160), | hashToHashId(crypto.RIPEMD160), | ||||
| @@ -0,0 +1,11 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build !amd64 gccgo appengine | |||||
| package poly1305 | |||||
| type mac struct{ macGeneric } | |||||
| func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} } | |||||
| @@ -2,21 +2,19 @@ | |||||
| // 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. | ||||
| /* | |||||
| Package poly1305 implements Poly1305 one-time message authentication code as | |||||
| specified in https://cr.yp.to/mac/poly1305-20050329.pdf. | |||||
| Poly1305 is a fast, one-time authentication function. It is infeasible for an | |||||
| attacker to generate an authenticator for a message without the key. However, a | |||||
| key must only be used for a single message. Authenticating two different | |||||
| messages with the same key allows an attacker to forge authenticators for other | |||||
| messages with the same key. | |||||
| Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was | |||||
| used with a fixed key in order to generate one-time keys from an nonce. | |||||
| However, in this package AES isn't used and the one-time key is specified | |||||
| directly. | |||||
| */ | |||||
| // Package poly1305 implements Poly1305 one-time message authentication code as | |||||
| // specified in https://cr.yp.to/mac/poly1305-20050329.pdf. | |||||
| // | |||||
| // Poly1305 is a fast, one-time authentication function. It is infeasible for an | |||||
| // attacker to generate an authenticator for a message without the key. However, a | |||||
| // key must only be used for a single message. Authenticating two different | |||||
| // messages with the same key allows an attacker to forge authenticators for other | |||||
| // messages with the same key. | |||||
| // | |||||
| // Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was | |||||
| // used with a fixed key in order to generate one-time keys from an nonce. | |||||
| // However, in this package AES isn't used and the one-time key is specified | |||||
| // directly. | |||||
| package poly1305 // import "golang.org/x/crypto/poly1305" | package poly1305 // import "golang.org/x/crypto/poly1305" | ||||
| import "crypto/subtle" | import "crypto/subtle" | ||||
| @@ -31,3 +29,55 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { | |||||
| Sum(&tmp, m, key) | Sum(&tmp, m, key) | ||||
| return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 | return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1 | ||||
| } | } | ||||
| // New returns a new MAC computing an authentication | |||||
| // tag of all data written to it with the given key. | |||||
| // This allows writing the message progressively instead | |||||
| // of passing it as a single slice. Common users should use | |||||
| // the Sum function instead. | |||||
| // | |||||
| // The key must be unique for each message, as authenticating | |||||
| // two different messages with the same key allows an attacker | |||||
| // to forge messages at will. | |||||
| func New(key *[32]byte) *MAC { | |||||
| return &MAC{ | |||||
| mac: newMAC(key), | |||||
| finalized: false, | |||||
| } | |||||
| } | |||||
| // MAC is an io.Writer computing an authentication tag | |||||
| // of the data written to it. | |||||
| // | |||||
| // MAC cannot be used like common hash.Hash implementations, | |||||
| // because using a poly1305 key twice breaks its security. | |||||
| // Therefore writing data to a running MAC after calling | |||||
| // Sum causes it to panic. | |||||
| type MAC struct { | |||||
| mac // platform-dependent implementation | |||||
| finalized bool | |||||
| } | |||||
| // Size returns the number of bytes Sum will return. | |||||
| func (h *MAC) Size() int { return TagSize } | |||||
| // Write adds more data to the running message authentication code. | |||||
| // It never returns an error. | |||||
| // | |||||
| // It must not be called after the first call of Sum. | |||||
| func (h *MAC) Write(p []byte) (n int, err error) { | |||||
| if h.finalized { | |||||
| panic("poly1305: write to MAC after Sum") | |||||
| } | |||||
| return h.mac.Write(p) | |||||
| } | |||||
| // Sum computes the authenticator of all data written to the | |||||
| // message authentication code. | |||||
| func (h *MAC) Sum(b []byte) []byte { | |||||
| var mac [TagSize]byte | |||||
| h.mac.Sum(&mac) | |||||
| h.finalized = true | |||||
| return append(b, mac[:]...) | |||||
| } | |||||
| @@ -6,17 +6,63 @@ | |||||
| package poly1305 | package poly1305 | ||||
| // This function is implemented in sum_amd64.s | |||||
| //go:noescape | //go:noescape | ||||
| func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte) | |||||
| func initialize(state *[7]uint64, key *[32]byte) | |||||
| //go:noescape | |||||
| func update(state *[7]uint64, msg []byte) | |||||
| //go:noescape | |||||
| func finalize(tag *[TagSize]byte, state *[7]uint64) | |||||
| // Sum generates an authenticator for m using a one-time key and puts the | // Sum generates an authenticator for m using a one-time key and puts the | ||||
| // 16-byte result into out. Authenticating two different messages with the same | // 16-byte result into out. Authenticating two different messages with the same | ||||
| // key allows an attacker to forge messages at will. | // key allows an attacker to forge messages at will. | ||||
| func Sum(out *[16]byte, m []byte, key *[32]byte) { | func Sum(out *[16]byte, m []byte, key *[32]byte) { | ||||
| var mPtr *byte | |||||
| if len(m) > 0 { | |||||
| mPtr = &m[0] | |||||
| h := newMAC(key) | |||||
| h.Write(m) | |||||
| h.Sum(out) | |||||
| } | |||||
| func newMAC(key *[32]byte) (h mac) { | |||||
| initialize(&h.state, key) | |||||
| return | |||||
| } | |||||
| type mac struct { | |||||
| state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 } | |||||
| buffer [TagSize]byte | |||||
| offset int | |||||
| } | |||||
| func (h *mac) Write(p []byte) (n int, err error) { | |||||
| n = len(p) | |||||
| if h.offset > 0 { | |||||
| remaining := TagSize - h.offset | |||||
| if n < remaining { | |||||
| h.offset += copy(h.buffer[h.offset:], p) | |||||
| return n, nil | |||||
| } | |||||
| copy(h.buffer[h.offset:], p[:remaining]) | |||||
| p = p[remaining:] | |||||
| h.offset = 0 | |||||
| update(&h.state, h.buffer[:]) | |||||
| } | |||||
| if nn := len(p) - (len(p) % TagSize); nn > 0 { | |||||
| update(&h.state, p[:nn]) | |||||
| p = p[nn:] | |||||
| } | |||||
| if len(p) > 0 { | |||||
| h.offset += copy(h.buffer[h.offset:], p) | |||||
| } | |||||
| return n, nil | |||||
| } | |||||
| func (h *mac) Sum(out *[16]byte) { | |||||
| state := h.state | |||||
| if h.offset > 0 { | |||||
| update(&state, h.buffer[:h.offset]) | |||||
| } | } | ||||
| poly1305(out, mPtr, uint64(len(m)), key) | |||||
| finalize(out, &state) | |||||
| } | } | ||||
| @@ -58,20 +58,17 @@ DATA ·poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF | |||||
| DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC | DATA ·poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC | ||||
| GLOBL ·poly1305Mask<>(SB), RODATA, $16 | GLOBL ·poly1305Mask<>(SB), RODATA, $16 | ||||
| // func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key) | |||||
| TEXT ·poly1305(SB), $0-32 | |||||
| MOVQ out+0(FP), DI | |||||
| MOVQ m+8(FP), SI | |||||
| MOVQ mlen+16(FP), R15 | |||||
| MOVQ key+24(FP), AX | |||||
| MOVQ 0(AX), R11 | |||||
| MOVQ 8(AX), R12 | |||||
| ANDQ ·poly1305Mask<>(SB), R11 // r0 | |||||
| ANDQ ·poly1305Mask<>+8(SB), R12 // r1 | |||||
| XORQ R8, R8 // h0 | |||||
| XORQ R9, R9 // h1 | |||||
| XORQ R10, R10 // h2 | |||||
| // func update(state *[7]uint64, msg []byte) | |||||
| TEXT ·update(SB), $0-32 | |||||
| MOVQ state+0(FP), DI | |||||
| MOVQ msg_base+8(FP), SI | |||||
| MOVQ msg_len+16(FP), R15 | |||||
| MOVQ 0(DI), R8 // h0 | |||||
| MOVQ 8(DI), R9 // h1 | |||||
| MOVQ 16(DI), R10 // h2 | |||||
| MOVQ 24(DI), R11 // r0 | |||||
| MOVQ 32(DI), R12 // r1 | |||||
| CMPQ R15, $16 | CMPQ R15, $16 | ||||
| JB bytes_between_0_and_15 | JB bytes_between_0_and_15 | ||||
| @@ -109,16 +106,42 @@ flush_buffer: | |||||
| JMP multiply | JMP multiply | ||||
| done: | done: | ||||
| MOVQ R8, AX | |||||
| MOVQ R9, BX | |||||
| MOVQ R8, 0(DI) | |||||
| MOVQ R9, 8(DI) | |||||
| MOVQ R10, 16(DI) | |||||
| RET | |||||
| // func initialize(state *[7]uint64, key *[32]byte) | |||||
| TEXT ·initialize(SB), $0-16 | |||||
| MOVQ state+0(FP), DI | |||||
| MOVQ key+8(FP), SI | |||||
| // state[0...7] is initialized with zero | |||||
| MOVOU 0(SI), X0 | |||||
| MOVOU 16(SI), X1 | |||||
| MOVOU ·poly1305Mask<>(SB), X2 | |||||
| PAND X2, X0 | |||||
| MOVOU X0, 24(DI) | |||||
| MOVOU X1, 40(DI) | |||||
| RET | |||||
| // func finalize(tag *[TagSize]byte, state *[7]uint64) | |||||
| TEXT ·finalize(SB), $0-16 | |||||
| MOVQ tag+0(FP), DI | |||||
| MOVQ state+8(FP), SI | |||||
| MOVQ 0(SI), AX | |||||
| MOVQ 8(SI), BX | |||||
| MOVQ 16(SI), CX | |||||
| MOVQ AX, R8 | |||||
| MOVQ BX, R9 | |||||
| SUBQ $0xFFFFFFFFFFFFFFFB, AX | SUBQ $0xFFFFFFFFFFFFFFFB, AX | ||||
| SBBQ $0xFFFFFFFFFFFFFFFF, BX | SBBQ $0xFFFFFFFFFFFFFFFF, BX | ||||
| SBBQ $3, R10 | |||||
| SBBQ $3, CX | |||||
| CMOVQCS R8, AX | CMOVQCS R8, AX | ||||
| CMOVQCS R9, BX | CMOVQCS R9, BX | ||||
| MOVQ key+24(FP), R8 | |||||
| ADDQ 16(R8), AX | |||||
| ADCQ 24(R8), BX | |||||
| ADDQ 40(SI), AX | |||||
| ADCQ 48(SI), BX | |||||
| MOVQ AX, 0(DI) | MOVQ AX, 0(DI) | ||||
| MOVQ BX, 8(DI) | MOVQ BX, 8(DI) | ||||
| @@ -1,4 +1,4 @@ | |||||
| // Copyright 2012 The Go Authors. All rights reserved. | |||||
| // Copyright 2018 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. | ||||
| @@ -6,21 +6,79 @@ package poly1305 | |||||
| import "encoding/binary" | import "encoding/binary" | ||||
| const ( | |||||
| msgBlock = uint32(1 << 24) | |||||
| finalBlock = uint32(0) | |||||
| ) | |||||
| // sumGeneric generates an authenticator for msg using a one-time key and | // sumGeneric generates an authenticator for msg using a one-time key and | ||||
| // puts the 16-byte result into out. This is the generic implementation of | // puts the 16-byte result into out. This is the generic implementation of | ||||
| // Sum and should be called if no assembly implementation is available. | // Sum and should be called if no assembly implementation is available. | ||||
| func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { | func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { | ||||
| var ( | |||||
| h0, h1, h2, h3, h4 uint32 // the hash accumulators | |||||
| r0, r1, r2, r3, r4 uint64 // the r part of the key | |||||
| ) | |||||
| h := newMACGeneric(key) | |||||
| h.Write(msg) | |||||
| h.Sum(out) | |||||
| } | |||||
| func newMACGeneric(key *[32]byte) (h macGeneric) { | |||||
| h.r[0] = binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff | |||||
| h.r[1] = (binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03 | |||||
| h.r[2] = (binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff | |||||
| h.r[3] = (binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff | |||||
| h.r[4] = (binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff | |||||
| h.s[0] = binary.LittleEndian.Uint32(key[16:]) | |||||
| h.s[1] = binary.LittleEndian.Uint32(key[20:]) | |||||
| h.s[2] = binary.LittleEndian.Uint32(key[24:]) | |||||
| h.s[3] = binary.LittleEndian.Uint32(key[28:]) | |||||
| return | |||||
| } | |||||
| type macGeneric struct { | |||||
| h, r [5]uint32 | |||||
| s [4]uint32 | |||||
| buffer [TagSize]byte | |||||
| offset int | |||||
| } | |||||
| func (h *macGeneric) Write(p []byte) (n int, err error) { | |||||
| n = len(p) | |||||
| if h.offset > 0 { | |||||
| remaining := TagSize - h.offset | |||||
| if n < remaining { | |||||
| h.offset += copy(h.buffer[h.offset:], p) | |||||
| return n, nil | |||||
| } | |||||
| copy(h.buffer[h.offset:], p[:remaining]) | |||||
| p = p[remaining:] | |||||
| h.offset = 0 | |||||
| updateGeneric(h.buffer[:], msgBlock, &(h.h), &(h.r)) | |||||
| } | |||||
| if nn := len(p) - (len(p) % TagSize); nn > 0 { | |||||
| updateGeneric(p, msgBlock, &(h.h), &(h.r)) | |||||
| p = p[nn:] | |||||
| } | |||||
| if len(p) > 0 { | |||||
| h.offset += copy(h.buffer[h.offset:], p) | |||||
| } | |||||
| return n, nil | |||||
| } | |||||
| r0 = uint64(binary.LittleEndian.Uint32(key[0:]) & 0x3ffffff) | |||||
| r1 = uint64((binary.LittleEndian.Uint32(key[3:]) >> 2) & 0x3ffff03) | |||||
| r2 = uint64((binary.LittleEndian.Uint32(key[6:]) >> 4) & 0x3ffc0ff) | |||||
| r3 = uint64((binary.LittleEndian.Uint32(key[9:]) >> 6) & 0x3f03fff) | |||||
| r4 = uint64((binary.LittleEndian.Uint32(key[12:]) >> 8) & 0x00fffff) | |||||
| func (h *macGeneric) Sum(out *[16]byte) { | |||||
| H, R := h.h, h.r | |||||
| if h.offset > 0 { | |||||
| var buffer [TagSize]byte | |||||
| copy(buffer[:], h.buffer[:h.offset]) | |||||
| buffer[h.offset] = 1 // invariant: h.offset < TagSize | |||||
| updateGeneric(buffer[:], finalBlock, &H, &R) | |||||
| } | |||||
| finalizeGeneric(out, &H, &(h.s)) | |||||
| } | |||||
| func updateGeneric(msg []byte, flag uint32, h, r *[5]uint32) { | |||||
| h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4] | |||||
| r0, r1, r2, r3, r4 := uint64(r[0]), uint64(r[1]), uint64(r[2]), uint64(r[3]), uint64(r[4]) | |||||
| R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5 | R1, R2, R3, R4 := r1*5, r2*5, r3*5, r4*5 | ||||
| for len(msg) >= TagSize { | for len(msg) >= TagSize { | ||||
| @@ -29,7 +87,7 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { | |||||
| h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff | h1 += (binary.LittleEndian.Uint32(msg[3:]) >> 2) & 0x3ffffff | ||||
| h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff | h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 0x3ffffff | ||||
| h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff | h3 += (binary.LittleEndian.Uint32(msg[9:]) >> 6) & 0x3ffffff | ||||
| h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | (1 << 24) | |||||
| h4 += (binary.LittleEndian.Uint32(msg[12:]) >> 8) | flag | |||||
| // h *= r | // h *= r | ||||
| d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) | d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) | ||||
| @@ -52,36 +110,11 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { | |||||
| msg = msg[TagSize:] | msg = msg[TagSize:] | ||||
| } | } | ||||
| if len(msg) > 0 { | |||||
| var block [TagSize]byte | |||||
| off := copy(block[:], msg) | |||||
| block[off] = 0x01 | |||||
| // h += msg | |||||
| h0 += binary.LittleEndian.Uint32(block[0:]) & 0x3ffffff | |||||
| h1 += (binary.LittleEndian.Uint32(block[3:]) >> 2) & 0x3ffffff | |||||
| h2 += (binary.LittleEndian.Uint32(block[6:]) >> 4) & 0x3ffffff | |||||
| h3 += (binary.LittleEndian.Uint32(block[9:]) >> 6) & 0x3ffffff | |||||
| h4 += (binary.LittleEndian.Uint32(block[12:]) >> 8) | |||||
| // h *= r | |||||
| d0 := (uint64(h0) * r0) + (uint64(h1) * R4) + (uint64(h2) * R3) + (uint64(h3) * R2) + (uint64(h4) * R1) | |||||
| d1 := (d0 >> 26) + (uint64(h0) * r1) + (uint64(h1) * r0) + (uint64(h2) * R4) + (uint64(h3) * R3) + (uint64(h4) * R2) | |||||
| d2 := (d1 >> 26) + (uint64(h0) * r2) + (uint64(h1) * r1) + (uint64(h2) * r0) + (uint64(h3) * R4) + (uint64(h4) * R3) | |||||
| d3 := (d2 >> 26) + (uint64(h0) * r3) + (uint64(h1) * r2) + (uint64(h2) * r1) + (uint64(h3) * r0) + (uint64(h4) * R4) | |||||
| d4 := (d3 >> 26) + (uint64(h0) * r4) + (uint64(h1) * r3) + (uint64(h2) * r2) + (uint64(h3) * r1) + (uint64(h4) * r0) | |||||
| // h %= p | |||||
| h0 = uint32(d0) & 0x3ffffff | |||||
| h1 = uint32(d1) & 0x3ffffff | |||||
| h2 = uint32(d2) & 0x3ffffff | |||||
| h3 = uint32(d3) & 0x3ffffff | |||||
| h4 = uint32(d4) & 0x3ffffff | |||||
| h[0], h[1], h[2], h[3], h[4] = h0, h1, h2, h3, h4 | |||||
| } | |||||
| h0 += uint32(d4>>26) * 5 | |||||
| h1 += h0 >> 26 | |||||
| h0 = h0 & 0x3ffffff | |||||
| } | |||||
| func finalizeGeneric(out *[TagSize]byte, h *[5]uint32, s *[4]uint32) { | |||||
| h0, h1, h2, h3, h4 := h[0], h[1], h[2], h[3], h[4] | |||||
| // h %= p reduction | // h %= p reduction | ||||
| h2 += h1 >> 26 | h2 += h1 >> 26 | ||||
| @@ -123,13 +156,13 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { | |||||
| // s: the s part of the key | // s: the s part of the key | ||||
| // tag = (h + s) % (2^128) | // tag = (h + s) % (2^128) | ||||
| t := uint64(h0) + uint64(binary.LittleEndian.Uint32(key[16:])) | |||||
| t := uint64(h0) + uint64(s[0]) | |||||
| h0 = uint32(t) | h0 = uint32(t) | ||||
| t = uint64(h1) + uint64(binary.LittleEndian.Uint32(key[20:])) + (t >> 32) | |||||
| t = uint64(h1) + uint64(s[1]) + (t >> 32) | |||||
| h1 = uint32(t) | h1 = uint32(t) | ||||
| t = uint64(h2) + uint64(binary.LittleEndian.Uint32(key[24:])) + (t >> 32) | |||||
| t = uint64(h2) + uint64(s[2]) + (t >> 32) | |||||
| h2 = uint32(t) | h2 = uint32(t) | ||||
| t = uint64(h3) + uint64(binary.LittleEndian.Uint32(key[28:])) + (t >> 32) | |||||
| t = uint64(h3) + uint64(s[3]) + (t >> 32) | |||||
| h3 = uint32(t) | h3 = uint32(t) | ||||
| binary.LittleEndian.PutUint32(out[0:], h0) | binary.LittleEndian.PutUint32(out[0:], h0) | ||||
| @@ -10,5 +10,7 @@ package poly1305 | |||||
| // 16-byte result into out. Authenticating two different messages with the same | // 16-byte result into out. Authenticating two different messages with the same | ||||
| // key allows an attacker to forge messages at will. | // key allows an attacker to forge messages at will. | ||||
| func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { | func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { | ||||
| sumGeneric(out, msg, key) | |||||
| h := newMAC(key) | |||||
| h.Write(msg) | |||||
| h.Sum(out) | |||||
| } | } | ||||
| @@ -6,16 +6,9 @@ | |||||
| package poly1305 | package poly1305 | ||||
| // hasVectorFacility reports whether the machine supports | |||||
| // the vector facility (vx). | |||||
| func hasVectorFacility() bool | |||||
| // hasVMSLFacility reports whether the machine supports | |||||
| // Vector Multiply Sum Logical (VMSL). | |||||
| func hasVMSLFacility() bool | |||||
| var hasVX = hasVectorFacility() | |||||
| var hasVMSL = hasVMSLFacility() | |||||
| import ( | |||||
| "golang.org/x/sys/cpu" | |||||
| ) | |||||
| // poly1305vx is an assembly implementation of Poly1305 that uses vector | // poly1305vx 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 | ||||
| @@ -33,12 +26,12 @@ func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte) | |||||
| // 16-byte result into out. Authenticating two different messages with the same | // 16-byte result into out. Authenticating two different messages with the same | ||||
| // key allows an attacker to forge messages at will. | // key allows an attacker to forge messages at will. | ||||
| func Sum(out *[16]byte, m []byte, key *[32]byte) { | func Sum(out *[16]byte, m []byte, key *[32]byte) { | ||||
| if hasVX { | |||||
| if cpu.S390X.HasVX { | |||||
| var mPtr *byte | var mPtr *byte | ||||
| if len(m) > 0 { | if len(m) > 0 { | ||||
| mPtr = &m[0] | mPtr = &m[0] | ||||
| } | } | ||||
| if hasVMSL && len(m) > 256 { | |||||
| if cpu.S390X.HasVXE && len(m) > 256 { | |||||
| poly1305vmsl(out, mPtr, uint64(len(m)), key) | poly1305vmsl(out, mPtr, uint64(len(m)), key) | ||||
| } else { | } else { | ||||
| poly1305vx(out, mPtr, uint64(len(m)), key) | poly1305vx(out, mPtr, uint64(len(m)), key) | ||||
| @@ -376,25 +376,3 @@ b1: | |||||
| MOVD $0, R3 | MOVD $0, R3 | ||||
| BR multiply | BR multiply | ||||
| TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 | |||||
| MOVD $x-24(SP), R1 | |||||
| XC $24, 0(R1), 0(R1) // clear the storage | |||||
| MOVD $2, R0 // R0 is the number of double words stored -1 | |||||
| WORD $0xB2B01000 // STFLE 0(R1) | |||||
| XOR R0, R0 // reset the value of R0 | |||||
| MOVBZ z-8(SP), R1 | |||||
| AND $0x40, R1 | |||||
| BEQ novector | |||||
| vectorinstalled: | |||||
| // check if the vector instruction has been enabled | |||||
| VLEIB $0, $0xF, V16 | |||||
| VLGVB $0, V16, R1 | |||||
| CMPBNE R1, $0xF, novector | |||||
| MOVB $1, ret+0(FP) // have vx | |||||
| RET | |||||
| novector: | |||||
| MOVB $0, ret+0(FP) // no vx | |||||
| RET | |||||
| @@ -907,25 +907,3 @@ square: | |||||
| MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) | ||||
| REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) | REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) | ||||
| BR next | BR next | ||||
| TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1 | |||||
| MOVD $x-24(SP), R1 | |||||
| XC $24, 0(R1), 0(R1) // clear the storage | |||||
| MOVD $2, R0 // R0 is the number of double words stored -1 | |||||
| WORD $0xB2B01000 // STFLE 0(R1) | |||||
| XOR R0, R0 // reset the value of R0 | |||||
| MOVBZ z-8(SP), R1 | |||||
| AND $0x01, R1 | |||||
| BEQ novmsl | |||||
| vectorinstalled: | |||||
| // check if the vector instruction has been enabled | |||||
| VLEIB $0, $0xF, V16 | |||||
| VLGVB $0, V16, R1 | |||||
| CMPBNE R1, $0xF, novmsl | |||||
| MOVB $1, ret+0(FP) // have vx | |||||
| RET | |||||
| novmsl: | |||||
| MOVB $0, ret+0(FP) // no vx | |||||
| RET | |||||
| @@ -25,10 +25,22 @@ 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" | ||||
| ) | ) | ||||
| // SignatureFlags represent additional flags that can be passed to the signature | |||||
| // requests an defined in [PROTOCOL.agent] section 4.5.1. | |||||
| type SignatureFlags uint32 | |||||
| // SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. | |||||
| const ( | |||||
| SignatureFlagReserved SignatureFlags = 1 << iota | |||||
| SignatureFlagRsaSha256 | |||||
| SignatureFlagRsaSha512 | |||||
| ) | |||||
| // Agent represents the capabilities of an ssh-agent. | // Agent represents the capabilities of an ssh-agent. | ||||
| type Agent interface { | type Agent interface { | ||||
| // List returns the identities known to the agent. | // List returns the identities known to the agent. | ||||
| @@ -57,6 +69,26 @@ type Agent interface { | |||||
| Signers() ([]ssh.Signer, error) | Signers() ([]ssh.Signer, error) | ||||
| } | } | ||||
| type ExtendedAgent interface { | |||||
| Agent | |||||
| // SignWithFlags signs like Sign, but allows for additional flags to be sent/received | |||||
| SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) | |||||
| // Extension processes a custom extension request. Standard-compliant agents are not | |||||
| // required to support any extensions, but this method allows agents to implement | |||||
| // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. | |||||
| // If agent extensions are unsupported entirely this method MUST return an | |||||
| // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in | |||||
| // the request is unsupported by the agent then ErrExtensionUnsupported MUST be | |||||
| // returned. | |||||
| // | |||||
| // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents | |||||
| // of the response are unspecified (including the type of the message), the complete | |||||
| // response will be returned as a []byte slice, including the "type" byte of the message. | |||||
| Extension(extensionType string, contents []byte) ([]byte, error) | |||||
| } | |||||
| // ConstraintExtension describes an optional constraint defined by users. | // ConstraintExtension describes an optional constraint defined by users. | ||||
| 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 | ||||
| @@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct { | |||||
| Rest []byte `ssh:"rest"` | Rest []byte `ssh:"rest"` | ||||
| } | } | ||||
| // See [PROTOCOL.agent], section 4.7 | |||||
| const agentExtension = 27 | |||||
| const agentExtensionFailure = 28 | |||||
| // ErrExtensionUnsupported indicates that an extension defined in | |||||
| // [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this | |||||
| // error indicates that the agent returned a standard SSH_AGENT_FAILURE message | |||||
| // as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol | |||||
| // specification (and therefore this error) does not distinguish between a | |||||
| // specific extension being unsupported and extensions being unsupported entirely. | |||||
| var ErrExtensionUnsupported = errors.New("agent: extension unsupported") | |||||
| type extensionAgentMsg struct { | |||||
| ExtensionType string `sshtype:"27"` | |||||
| Contents []byte | |||||
| } | |||||
| // Key represents a protocol 2 public key as defined in | // Key represents a protocol 2 public key as defined in | ||||
| // [PROTOCOL.agent], section 2.5.2. | // [PROTOCOL.agent], section 2.5.2. | ||||
| type Key struct { | type Key struct { | ||||
| @@ -260,7 +309,7 @@ type client struct { | |||||
| // NewClient returns an Agent that talks to an ssh-agent process over | // NewClient returns an Agent that talks to an ssh-agent process over | ||||
| // the given connection. | // the given connection. | ||||
| func NewClient(rw io.ReadWriter) Agent { | |||||
| func NewClient(rw io.ReadWriter) ExtendedAgent { | |||||
| return &client{conn: rw} | return &client{conn: rw} | ||||
| } | } | ||||
| @@ -268,6 +317,21 @@ func NewClient(rw io.ReadWriter) Agent { | |||||
| // unmarshaled into reply and replyType is set to the first byte of | // unmarshaled into reply and replyType is set to the first byte of | ||||
| // the reply, which contains the type of the message. | // the reply, which contains the type of the message. | ||||
| func (c *client) call(req []byte) (reply interface{}, err error) { | func (c *client) call(req []byte) (reply interface{}, err error) { | ||||
| buf, err := c.callRaw(req) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| reply, err = unmarshal(buf) | |||||
| if err != nil { | |||||
| return nil, clientErr(err) | |||||
| } | |||||
| return reply, nil | |||||
| } | |||||
| // callRaw sends an RPC to the agent. On success, the raw | |||||
| // bytes of the response are returned; no unmarshalling is | |||||
| // performed on the response. | |||||
| func (c *client) callRaw(req []byte) (reply []byte, err error) { | |||||
| c.mu.Lock() | c.mu.Lock() | ||||
| defer c.mu.Unlock() | defer c.mu.Unlock() | ||||
| @@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) { | |||||
| } | } | ||||
| respSize := binary.BigEndian.Uint32(respSizeBuf[:]) | respSize := binary.BigEndian.Uint32(respSizeBuf[:]) | ||||
| if respSize > maxAgentResponseBytes { | if respSize > maxAgentResponseBytes { | ||||
| return nil, clientErr(err) | |||||
| return nil, clientErr(errors.New("response too large")) | |||||
| } | } | ||||
| buf := make([]byte, respSize) | buf := make([]byte, respSize) | ||||
| if _, err = io.ReadFull(c.conn, buf); err != nil { | if _, err = io.ReadFull(c.conn, buf); err != nil { | ||||
| return nil, clientErr(err) | return nil, clientErr(err) | ||||
| } | } | ||||
| reply, err = unmarshal(buf) | |||||
| if err != nil { | |||||
| return nil, clientErr(err) | |||||
| } | |||||
| return reply, err | |||||
| return buf, nil | |||||
| } | } | ||||
| func (c *client) simpleCall(req []byte) error { | func (c *client) simpleCall(req []byte) error { | ||||
| @@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) { | |||||
| // Sign has the agent sign the data using a protocol 2 key as defined | // Sign has the agent sign the data using a protocol 2 key as defined | ||||
| // in [PROTOCOL.agent] section 2.6.2. | // in [PROTOCOL.agent] section 2.6.2. | ||||
| func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | ||||
| return c.SignWithFlags(key, data, 0) | |||||
| } | |||||
| func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { | |||||
| req := ssh.Marshal(signRequestAgentMsg{ | req := ssh.Marshal(signRequestAgentMsg{ | ||||
| KeyBlob: key.Marshal(), | KeyBlob: key.Marshal(), | ||||
| Data: data, | Data: data, | ||||
| Flags: uint32(flags), | |||||
| }) | }) | ||||
| msg, err := c.call(req) | msg, err := c.call(req) | ||||
| @@ -681,3 +746,44 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, | |||||
| // The agent has its own entropy source, so the rand argument is ignored. | // The agent has its own entropy source, so the rand argument is ignored. | ||||
| 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) { | |||||
| var flags SignatureFlags | |||||
| if opts != nil { | |||||
| switch opts.HashFunc() { | |||||
| case crypto.SHA256: | |||||
| flags = SignatureFlagRsaSha256 | |||||
| case crypto.SHA512: | |||||
| flags = SignatureFlagRsaSha512 | |||||
| } | |||||
| } | |||||
| return s.agent.SignWithFlags(s.pub, data, flags) | |||||
| } | |||||
| // 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 | |||||
| // type of the response is up to the implementation, this returns the bytes of the | |||||
| // response and does not attempt any type of unmarshalling. | |||||
| func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { | |||||
| req := ssh.Marshal(extensionAgentMsg{ | |||||
| ExtensionType: extensionType, | |||||
| Contents: contents, | |||||
| }) | |||||
| buf, err := c.callRaw(req) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if len(buf) == 0 { | |||||
| return nil, errors.New("agent: failure; empty response") | |||||
| } | |||||
| // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message | |||||
| // represents an agent that does not support the extension | |||||
| if buf[0] == agentFailure { | |||||
| return nil, ErrExtensionUnsupported | |||||
| } | |||||
| if buf[0] == agentExtensionFailure { | |||||
| return nil, errors.New("agent: generic extension failure") | |||||
| } | |||||
| return buf, nil | |||||
| } | |||||
| @@ -182,6 +182,10 @@ func (r *keyring) Add(key AddedKey) error { | |||||
| // Sign returns a signature for the data. | // Sign returns a signature for the data. | ||||
| func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | ||||
| return r.SignWithFlags(key, data, 0) | |||||
| } | |||||
| func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { | |||||
| r.mu.Lock() | r.mu.Lock() | ||||
| defer r.mu.Unlock() | defer r.mu.Unlock() | ||||
| if r.locked { | if r.locked { | ||||
| @@ -192,7 +196,24 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | |||||
| wanted := key.Marshal() | wanted := key.Marshal() | ||||
| for _, k := range r.keys { | for _, k := range r.keys { | ||||
| if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { | if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { | ||||
| return k.signer.Sign(rand.Reader, data) | |||||
| if flags == 0 { | |||||
| return k.signer.Sign(rand.Reader, data) | |||||
| } else { | |||||
| if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { | |||||
| return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) | |||||
| } else { | |||||
| var algorithm string | |||||
| switch flags { | |||||
| case SignatureFlagRsaSha256: | |||||
| algorithm = ssh.SigAlgoRSASHA2256 | |||||
| case SignatureFlagRsaSha512: | |||||
| algorithm = ssh.SigAlgoRSASHA2512 | |||||
| default: | |||||
| return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) | |||||
| } | |||||
| return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) | |||||
| } | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| return nil, errors.New("not found") | return nil, errors.New("not found") | ||||
| @@ -213,3 +234,8 @@ func (r *keyring) Signers() ([]ssh.Signer, error) { | |||||
| } | } | ||||
| return s, nil | return s, nil | ||||
| } | } | ||||
| // The keyring does not support any extensions | |||||
| func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { | |||||
| return nil, ErrExtensionUnsupported | |||||
| } | |||||
| @@ -128,7 +128,14 @@ func (s *server) processRequest(data []byte) (interface{}, error) { | |||||
| Blob: req.KeyBlob, | Blob: req.KeyBlob, | ||||
| } | } | ||||
| sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. | |||||
| var sig *ssh.Signature | |||||
| var err error | |||||
| if extendedAgent, ok := s.agent.(ExtendedAgent); ok { | |||||
| sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) | |||||
| } else { | |||||
| sig, err = s.agent.Sign(k, req.Data) | |||||
| } | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) { | |||||
| case agentAddIDConstrained, agentAddIdentity: | case agentAddIDConstrained, agentAddIdentity: | ||||
| return nil, s.insertIdentity(data) | return nil, s.insertIdentity(data) | ||||
| case agentExtension: | |||||
| // Return a stub object where the whole contents of the response gets marshaled. | |||||
| var responseStub struct { | |||||
| Rest []byte `ssh:"rest"` | |||||
| } | |||||
| if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { | |||||
| // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 | |||||
| // requires that we return a standard SSH_AGENT_FAILURE message. | |||||
| responseStub.Rest = []byte{agentFailure} | |||||
| } else { | |||||
| var req extensionAgentMsg | |||||
| if err := ssh.Unmarshal(data, &req); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) | |||||
| if err != nil { | |||||
| // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE | |||||
| // message as required by [PROTOCOL.agent] section 4.7. | |||||
| if err == ErrExtensionUnsupported { | |||||
| responseStub.Rest = []byte{agentFailure} | |||||
| } else { | |||||
| // As the result of any other error processing an extension request, | |||||
| // [PROTOCOL.agent] section 4.7 requires that we return a | |||||
| // SSH_AGENT_EXTENSION_FAILURE code. | |||||
| responseStub.Rest = []byte{agentExtensionFailure} | |||||
| } | |||||
| } else { | |||||
| if len(res) == 0 { | |||||
| return nil, nil | |||||
| } | |||||
| responseStub.Rest = res | |||||
| } | |||||
| } | |||||
| return responseStub, nil | |||||
| } | } | ||||
| return nil, fmt.Errorf("unknown opcode %d", data[0]) | return nil, fmt.Errorf("unknown opcode %d", data[0]) | ||||
| @@ -497,6 +541,9 @@ func ServeAgent(agent Agent, c io.ReadWriter) error { | |||||
| return err | return err | ||||
| } | } | ||||
| l := binary.BigEndian.Uint32(length[:]) | l := binary.BigEndian.Uint32(length[:]) | ||||
| if l == 0 { | |||||
| return fmt.Errorf("agent: request size is 0") | |||||
| } | |||||
| if l > maxAgentResponseBytes { | if l > maxAgentResponseBytes { | ||||
| // We also cap requests. | // We also cap requests. | ||||
| return fmt.Errorf("agent: request too large: %d", l) | return fmt.Errorf("agent: request too large: %d", l) | ||||
| @@ -222,6 +222,11 @@ type openSSHCertSigner struct { | |||||
| signer Signer | signer Signer | ||||
| } | } | ||||
| type algorithmOpenSSHCertSigner struct { | |||||
| *openSSHCertSigner | |||||
| algorithmSigner AlgorithmSigner | |||||
| } | |||||
| // NewCertSigner returns a Signer that signs with the given Certificate, whose | // NewCertSigner returns a Signer that signs with the given Certificate, whose | ||||
| // 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. | ||||
| @@ -230,7 +235,12 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { | |||||
| return nil, errors.New("ssh: signer and cert have different public key") | return nil, errors.New("ssh: signer and cert have different public key") | ||||
| } | } | ||||
| return &openSSHCertSigner{cert, signer}, nil | |||||
| if algorithmSigner, ok := signer.(AlgorithmSigner); ok { | |||||
| return &algorithmOpenSSHCertSigner{ | |||||
| &openSSHCertSigner{cert, signer}, algorithmSigner}, nil | |||||
| } else { | |||||
| return &openSSHCertSigner{cert, signer}, nil | |||||
| } | |||||
| } | } | ||||
| func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||||
| @@ -241,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey { | |||||
| return s.pub | return s.pub | ||||
| } | } | ||||
| func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { | |||||
| return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) | |||||
| } | |||||
| const sourceAddressCriticalOption = "source-address" | const sourceAddressCriticalOption = "source-address" | ||||
| // CertChecker does the work of verifying a certificate. Its methods | // CertChecker does the work of verifying a certificate. Its methods | ||||
| @@ -149,8 +149,8 @@ type streamPacketCipher struct { | |||||
| macResult []byte | macResult []byte | ||||
| } | } | ||||
| // readPacket reads and decrypt a single packet from the reader argument. | |||||
| func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| // readCipherPacket reads and decrypt a single packet from the reader argument. | |||||
| func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| if _, err := io.ReadFull(r, s.prefix[:]); err != nil { | if _, err := io.ReadFull(r, s.prefix[:]); err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -221,8 +221,8 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err | |||||
| return s.packetData[:length-paddingLength-1], nil | return s.packetData[:length-paddingLength-1], nil | ||||
| } | } | ||||
| // writePacket encrypts and sends a packet of data to the writer argument | |||||
| func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | |||||
| // writeCipherPacket encrypts and sends a packet of data to the writer argument | |||||
| func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | |||||
| if len(packet) > maxPacket { | if len(packet) > maxPacket { | ||||
| return errors.New("ssh: packet too large") | return errors.New("ssh: packet too large") | ||||
| } | } | ||||
| @@ -327,7 +327,7 @@ func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) | |||||
| const gcmTagSize = 16 | const gcmTagSize = 16 | ||||
| func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | |||||
| func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | |||||
| // Pad out to multiple of 16 bytes. This is different from the | // Pad out to multiple of 16 bytes. This is different from the | ||||
| // stream cipher because that encrypts the length too. | // stream cipher because that encrypts the length too. | ||||
| padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) | padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) | ||||
| @@ -370,7 +370,7 @@ func (c *gcmCipher) incIV() { | |||||
| } | } | ||||
| } | } | ||||
| func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| if _, err := io.ReadFull(r, c.prefix[:]); err != nil { | if _, err := io.ReadFull(r, c.prefix[:]); err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -486,8 +486,8 @@ type cbcError string | |||||
| func (e cbcError) Error() string { return string(e) } | func (e cbcError) Error() string { return string(e) } | ||||
| func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| p, err := c.readPacketLeaky(seqNum, r) | |||||
| func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| p, err := c.readCipherPacketLeaky(seqNum, r) | |||||
| if err != nil { | if err != nil { | ||||
| if _, ok := err.(cbcError); ok { | if _, ok := err.(cbcError); ok { | ||||
| // Verification error: read a fixed amount of | // Verification error: read a fixed amount of | ||||
| @@ -500,7 +500,7 @@ func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| return p, err | return p, err | ||||
| } | } | ||||
| func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| blockSize := c.decrypter.BlockSize() | blockSize := c.decrypter.BlockSize() | ||||
| // Read the header, which will include some of the subsequent data in the | // Read the header, which will include some of the subsequent data in the | ||||
| @@ -576,7 +576,7 @@ func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) | |||||
| return c.packetData[prefixLen:paddingStart], nil | return c.packetData[prefixLen:paddingStart], nil | ||||
| } | } | ||||
| func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | |||||
| func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | |||||
| effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) | effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) | ||||
| // Length of encrypted portion of the packet (header, payload, padding). | // Length of encrypted portion of the packet (header, payload, padding). | ||||
| @@ -665,7 +665,7 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA | |||||
| return c, nil | return c, nil | ||||
| } | } | ||||
| func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { | |||||
| nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} | nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} | ||||
| s := chacha20.New(c.contentKey, nonce) | s := chacha20.New(c.contentKey, nonce) | ||||
| var polyKey [32]byte | var polyKey [32]byte | ||||
| @@ -723,7 +723,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, | |||||
| return plain, nil | return plain, nil | ||||
| } | } | ||||
| func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { | |||||
| func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { | |||||
| nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} | nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} | ||||
| s := chacha20.New(c.contentKey, nonce) | s := chacha20.New(c.contentKey, nonce) | ||||
| var polyKey [32]byte | var polyKey [32]byte | ||||
| @@ -185,7 +185,7 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) { | |||||
| // keys. A HostKeyCallback must return nil if the host key is OK, or | // keys. A HostKeyCallback must return nil if the host key is OK, or | ||||
| // an error to reject it. It receives the hostname as passed to Dial | // an error to reject it. It receives the hostname as passed to Dial | ||||
| // or NewClientConn. The remote address is the RemoteAddr of the | // or NewClientConn. The remote address is the RemoteAddr of the | ||||
| // net.Conn underlying the the SSH connection. | |||||
| // net.Conn underlying the SSH connection. | |||||
| type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error | type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error | ||||
| // BannerCallback is the function type used for treat the banner sent by | // BannerCallback is the function type used for treat the banner sent by | ||||
| @@ -109,6 +109,7 @@ func findCommon(what string, client []string, server []string) (common string, e | |||||
| return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) | return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) | ||||
| } | } | ||||
| // directionAlgorithms records algorithm choices in one direction (either read or write) | |||||
| type directionAlgorithms struct { | type directionAlgorithms struct { | ||||
| Cipher string | Cipher string | ||||
| MAC string | MAC string | ||||
| @@ -137,7 +138,7 @@ type algorithms struct { | |||||
| r directionAlgorithms | r directionAlgorithms | ||||
| } | } | ||||
| func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { | |||||
| func findAgreedAlgorithms(isClient bool, clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { | |||||
| result := &algorithms{} | result := &algorithms{} | ||||
| result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) | result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) | ||||
| @@ -150,32 +151,37 @@ func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor | |||||
| return | return | ||||
| } | } | ||||
| result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) | |||||
| stoc, ctos := &result.w, &result.r | |||||
| if isClient { | |||||
| ctos, stoc = stoc, ctos | |||||
| } | |||||
| ctos.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) | |||||
| if err != nil { | if err != nil { | ||||
| return | return | ||||
| } | } | ||||
| result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) | |||||
| stoc.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) | |||||
| if err != nil { | if err != nil { | ||||
| return | return | ||||
| } | } | ||||
| result.w.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 | ||||
| } | } | ||||
| result.r.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 | ||||
| } | } | ||||
| result.w.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 { | ||||
| return | return | ||||
| } | } | ||||
| result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) | |||||
| stoc.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) | |||||
| if err != nil { | if err != nil { | ||||
| return | return | ||||
| } | } | ||||
| @@ -543,7 +543,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | |||||
| clientInit := otherInit | clientInit := otherInit | ||||
| serverInit := t.sentInitMsg | serverInit := t.sentInitMsg | ||||
| if len(t.hostKeys) == 0 { | |||||
| isClient := len(t.hostKeys) == 0 | |||||
| if isClient { | |||||
| clientInit, serverInit = serverInit, clientInit | clientInit, serverInit = serverInit, clientInit | ||||
| magics.clientKexInit = t.sentInitPacket | magics.clientKexInit = t.sentInitPacket | ||||
| @@ -551,7 +552,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | |||||
| } | } | ||||
| var err error | var err error | ||||
| t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) | |||||
| t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit) | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| @@ -38,6 +38,16 @@ const ( | |||||
| KeyAlgoED25519 = "ssh-ed25519" | KeyAlgoED25519 = "ssh-ed25519" | ||||
| ) | ) | ||||
| // 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 ( | |||||
| SigAlgoRSA = "ssh-rsa" | |||||
| SigAlgoRSASHA2256 = "rsa-sha2-256" | |||||
| SigAlgoRSASHA2512 = "rsa-sha2-512" | |||||
| ) | |||||
| // parsePubKey parses a public key of the given algorithm. | // parsePubKey parses a public key of the given algorithm. | ||||
| // Use ParsePublicKey for keys with prepended algorithm. | // Use ParsePublicKey for keys with prepended algorithm. | ||||
| func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { | func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { | ||||
| @@ -301,6 +311,19 @@ type Signer interface { | |||||
| 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 | |||||
| // algorithm to use for signing. | |||||
| type AlgorithmSigner interface { | |||||
| Signer | |||||
| // SignWithAlgorithm is like Signer.Sign, but allows specification of a | |||||
| // non-default signing algorithm. See the SigAlgo* constants in this | |||||
| // package for signature algorithms supported by this package. Callers may | |||||
| // pass an empty string for the algorithm in which case the AlgorithmSigner | |||||
| // will use its default algorithm. | |||||
| SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) | |||||
| } | |||||
| type rsaPublicKey rsa.PublicKey | type rsaPublicKey rsa.PublicKey | ||||
| func (r *rsaPublicKey) Type() string { | func (r *rsaPublicKey) Type() string { | ||||
| @@ -349,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte { | |||||
| } | } | ||||
| func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { | func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { | ||||
| if sig.Format != r.Type() { | |||||
| var hash crypto.Hash | |||||
| switch 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()) | ||||
| } | } | ||||
| h := crypto.SHA1.New() | |||||
| h := hash.New() | |||||
| h.Write(data) | h.Write(data) | ||||
| digest := h.Sum(nil) | digest := h.Sum(nil) | ||||
| return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) | |||||
| return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) | |||||
| } | } | ||||
| func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { | func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { | ||||
| @@ -459,6 +490,14 @@ 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, "") | |||||
| } | |||||
| func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { | |||||
| if algorithm != "" && algorithm != k.PublicKey().Type() { | |||||
| return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) | |||||
| } | |||||
| h := crypto.SHA1.New() | h := crypto.SHA1.New() | ||||
| h.Write(data) | h.Write(data) | ||||
| digest := h.Sum(nil) | digest := h.Sum(nil) | ||||
| @@ -691,16 +730,42 @@ 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, "") | |||||
| } | |||||
| func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { | |||||
| var hashFunc crypto.Hash | var hashFunc crypto.Hash | ||||
| switch key := s.pubKey.(type) { | |||||
| case *rsaPublicKey, *dsaPublicKey: | |||||
| hashFunc = crypto.SHA1 | |||||
| case *ecdsaPublicKey: | |||||
| hashFunc = ecHash(key.Curve) | |||||
| case ed25519PublicKey: | |||||
| default: | |||||
| return nil, fmt.Errorf("ssh: unsupported key type %T", key) | |||||
| 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 == "" { | |||||
| 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) { | |||||
| case *dsaPublicKey: | |||||
| hashFunc = crypto.SHA1 | |||||
| case *ecdsaPublicKey: | |||||
| hashFunc = ecHash(key.Curve) | |||||
| case ed25519PublicKey: | |||||
| default: | |||||
| return nil, fmt.Errorf("ssh: unsupported key type %T", key) | |||||
| } | |||||
| } | } | ||||
| var digest []byte | var digest []byte | ||||
| @@ -745,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | |||||
| } | } | ||||
| return &Signature{ | return &Signature{ | ||||
| Format: s.pubKey.Type(), | |||||
| Format: algorithm, | |||||
| Blob: signature, | Blob: signature, | ||||
| }, nil | }, nil | ||||
| } | } | ||||
| @@ -350,8 +350,8 @@ func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.Public | |||||
| return db.checkAddr(hostToCheck, remoteKey) | return db.checkAddr(hostToCheck, remoteKey) | ||||
| } | } | ||||
| // checkAddrs checks if we can find the given public key for any of | |||||
| // the given addresses. If we only find an entry for the IP address, | |||||
| // checkAddr checks if we can find the given public key for the | |||||
| // given address. If we only find an entry for the IP address, | |||||
| // or only the hostname, then this still succeeds. | // or only the hostname, then this still succeeds. | ||||
| func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { | func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { | ||||
| // TODO(hanwen): are these the right semantics? What if there | // TODO(hanwen): are these the right semantics? What if there | ||||
| @@ -764,3 +764,29 @@ func decode(packet []byte) (interface{}, error) { | |||||
| } | } | ||||
| return msg, nil | return msg, nil | ||||
| } | } | ||||
| var packetTypeNames = map[byte]string{ | |||||
| msgDisconnect: "disconnectMsg", | |||||
| msgServiceRequest: "serviceRequestMsg", | |||||
| msgServiceAccept: "serviceAcceptMsg", | |||||
| msgKexInit: "kexInitMsg", | |||||
| msgKexDHInit: "kexDHInitMsg", | |||||
| msgKexDHReply: "kexDHReplyMsg", | |||||
| msgUserAuthRequest: "userAuthRequestMsg", | |||||
| msgUserAuthSuccess: "userAuthSuccessMsg", | |||||
| msgUserAuthFailure: "userAuthFailureMsg", | |||||
| msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg", | |||||
| msgGlobalRequest: "globalRequestMsg", | |||||
| msgRequestSuccess: "globalRequestSuccessMsg", | |||||
| msgRequestFailure: "globalRequestFailureMsg", | |||||
| msgChannelOpen: "channelOpenMsg", | |||||
| msgChannelData: "channelDataMsg", | |||||
| msgChannelOpenConfirm: "channelOpenConfirmMsg", | |||||
| msgChannelOpenFailure: "channelOpenFailureMsg", | |||||
| msgChannelWindowAdjust: "windowAdjustMsg", | |||||
| msgChannelEOF: "channelEOFMsg", | |||||
| msgChannelClose: "channelCloseMsg", | |||||
| msgChannelRequest: "channelRequestMsg", | |||||
| msgChannelSuccess: "channelRequestSuccessMsg", | |||||
| msgChannelFailure: "channelRequestFailureMsg", | |||||
| } | |||||
| @@ -404,7 +404,7 @@ userAuthLoop: | |||||
| perms, authErr = config.PasswordCallback(s, password) | perms, authErr = config.PasswordCallback(s, password) | ||||
| case "keyboard-interactive": | case "keyboard-interactive": | ||||
| if config.KeyboardInteractiveCallback == nil { | if config.KeyboardInteractiveCallback == nil { | ||||
| authErr = errors.New("ssh: keyboard-interactive auth not configubred") | |||||
| authErr = errors.New("ssh: keyboard-interactive auth not configured") | |||||
| break | break | ||||
| } | } | ||||
| @@ -484,6 +484,7 @@ userAuthLoop: | |||||
| // sig.Format. This is usually the same, but | // sig.Format. This is usually the same, but | ||||
| // for certs, the names differ. | // for certs, the names differ. | ||||
| if !isAcceptableAlgo(sig.Format) { | if !isAcceptableAlgo(sig.Format) { | ||||
| authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) | |||||
| break | break | ||||
| } | } | ||||
| signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) | signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) | ||||
| @@ -53,14 +53,14 @@ type transport struct { | |||||
| // packetCipher represents a combination of SSH encryption/MAC | // packetCipher represents a combination of SSH encryption/MAC | ||||
| // protocol. A single instance should be used for one direction only. | // protocol. A single instance should be used for one direction only. | ||||
| type packetCipher interface { | type packetCipher interface { | ||||
| // writePacket encrypts the packet and writes it to w. The | |||||
| // writeCipherPacket encrypts the packet and writes it to w. The | |||||
| // contents of the packet are generally scrambled. | // contents of the packet are generally scrambled. | ||||
| writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error | |||||
| writeCipherPacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error | |||||
| // readPacket reads and decrypts a packet of data. The | |||||
| // readCipherPacket reads and decrypts a packet of data. The | |||||
| // returned packet may be overwritten by future calls of | // returned packet may be overwritten by future calls of | ||||
| // readPacket. | // readPacket. | ||||
| readPacket(seqnum uint32, r io.Reader) ([]byte, error) | |||||
| readCipherPacket(seqnum uint32, r io.Reader) ([]byte, error) | |||||
| } | } | ||||
| // connectionState represents one side (read or write) of the | // connectionState represents one side (read or write) of the | ||||
| @@ -127,7 +127,7 @@ func (t *transport) readPacket() (p []byte, err error) { | |||||
| } | } | ||||
| func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { | func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { | ||||
| packet, err := s.packetCipher.readPacket(s.seqNum, r) | |||||
| packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) | |||||
| s.seqNum++ | s.seqNum++ | ||||
| if err == nil && len(packet) == 0 { | if err == nil && len(packet) == 0 { | ||||
| err = errors.New("ssh: zero length packet") | err = errors.New("ssh: zero length packet") | ||||
| @@ -175,7 +175,7 @@ func (t *transport) writePacket(packet []byte) error { | |||||
| func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { | func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { | ||||
| changeKeys := len(packet) > 0 && packet[0] == msgNewKeys | changeKeys := len(packet) > 0 && packet[0] == msgNewKeys | ||||
| err := s.packetCipher.writePacket(s.seqNum, w, rand, packet) | |||||
| err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| @@ -0,0 +1,30 @@ | |||||
| // 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. | |||||
| package cpu | |||||
| import ( | |||||
| "encoding/binary" | |||||
| "runtime" | |||||
| ) | |||||
| // hostByteOrder returns binary.LittleEndian on little-endian machines and | |||||
| // binary.BigEndian on big-endian machines. | |||||
| func hostByteOrder() binary.ByteOrder { | |||||
| switch runtime.GOARCH { | |||||
| case "386", "amd64", "amd64p32", | |||||
| "arm", "arm64", | |||||
| "mipsle", "mips64le", "mips64p32le", | |||||
| "ppc64le", | |||||
| "riscv", "riscv64": | |||||
| return binary.LittleEndian | |||||
| case "armbe", "arm64be", | |||||
| "mips", "mips64", "mips64p32", | |||||
| "ppc", "ppc64", | |||||
| "s390", "s390x", | |||||
| "sparc", "sparc64": | |||||
| return binary.BigEndian | |||||
| } | |||||
| panic("unknown architecture") | |||||
| } | |||||
| @@ -0,0 +1,126 @@ | |||||
| // Copyright 2018 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. | |||||
| // Package cpu implements processor feature detection for | |||||
| // various CPU architectures. | |||||
| package cpu | |||||
| // Initialized reports whether the CPU features were initialized. | |||||
| // | |||||
| // For some GOOS/GOARCH combinations initialization of the CPU features depends | |||||
| // on reading an operating specific file, e.g. /proc/self/auxv on linux/arm | |||||
| // Initialized will report false if reading the file fails. | |||||
| var Initialized bool | |||||
| // CacheLinePad is used to pad structs to avoid false sharing. | |||||
| type CacheLinePad struct{ _ [cacheLineSize]byte } | |||||
| // X86 contains the supported CPU features of the | |||||
| // current X86/AMD64 platform. If the current platform | |||||
| // is not X86/AMD64 then all feature flags are false. | |||||
| // | |||||
| // X86 is padded to avoid false sharing. Further the HasAVX | |||||
| // and HasAVX2 are only set if the OS supports XMM and YMM | |||||
| // registers in addition to the CPUID feature bit being set. | |||||
| var X86 struct { | |||||
| _ CacheLinePad | |||||
| HasAES bool // AES hardware implementation (AES NI) | |||||
| HasADX bool // Multi-precision add-carry instruction extensions | |||||
| HasAVX bool // Advanced vector extension | |||||
| HasAVX2 bool // Advanced vector extension 2 | |||||
| HasBMI1 bool // Bit manipulation instruction set 1 | |||||
| HasBMI2 bool // Bit manipulation instruction set 2 | |||||
| HasERMS bool // Enhanced REP for MOVSB and STOSB | |||||
| HasFMA bool // Fused-multiply-add instructions | |||||
| HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. | |||||
| HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM | |||||
| HasPOPCNT bool // Hamming weight instruction POPCNT. | |||||
| HasRDRAND bool // RDRAND instruction (on-chip random number generator) | |||||
| HasRDSEED bool // RDSEED instruction (on-chip random number generator) | |||||
| HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) | |||||
| HasSSE3 bool // Streaming SIMD extension 3 | |||||
| HasSSSE3 bool // Supplemental streaming SIMD extension 3 | |||||
| HasSSE41 bool // Streaming SIMD extension 4 and 4.1 | |||||
| HasSSE42 bool // Streaming SIMD extension 4 and 4.2 | |||||
| _ CacheLinePad | |||||
| } | |||||
| // ARM64 contains the supported CPU features of the | |||||
| // current ARMv8(aarch64) platform. If the current platform | |||||
| // is not arm64 then all feature flags are false. | |||||
| var ARM64 struct { | |||||
| _ CacheLinePad | |||||
| HasFP bool // Floating-point instruction set (always available) | |||||
| HasASIMD bool // Advanced SIMD (always available) | |||||
| HasEVTSTRM bool // Event stream support | |||||
| HasAES bool // AES hardware implementation | |||||
| HasPMULL bool // Polynomial multiplication instruction set | |||||
| HasSHA1 bool // SHA1 hardware implementation | |||||
| HasSHA2 bool // SHA2 hardware implementation | |||||
| HasCRC32 bool // CRC32 hardware implementation | |||||
| HasATOMICS bool // Atomic memory operation instruction set | |||||
| HasFPHP bool // Half precision floating-point instruction set | |||||
| HasASIMDHP bool // Advanced SIMD half precision instruction set | |||||
| HasCPUID bool // CPUID identification scheme registers | |||||
| HasASIMDRDM bool // Rounding double multiply add/subtract instruction set | |||||
| HasJSCVT bool // Javascript conversion from floating-point to integer | |||||
| HasFCMA bool // Floating-point multiplication and addition of complex numbers | |||||
| HasLRCPC bool // Release Consistent processor consistent support | |||||
| HasDCPOP bool // Persistent memory support | |||||
| HasSHA3 bool // SHA3 hardware implementation | |||||
| HasSM3 bool // SM3 hardware implementation | |||||
| HasSM4 bool // SM4 hardware implementation | |||||
| HasASIMDDP bool // Advanced SIMD double precision instruction set | |||||
| HasSHA512 bool // SHA512 hardware implementation | |||||
| HasSVE bool // Scalable Vector Extensions | |||||
| HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 | |||||
| _ CacheLinePad | |||||
| } | |||||
| // PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms. | |||||
| // If the current platform is not ppc64/ppc64le then all feature flags are false. | |||||
| // | |||||
| // For ppc64/ppc64le, it is safe to check only for ISA level starting on ISA v3.00, | |||||
| // since there are no optional categories. There are some exceptions that also | |||||
| // require kernel support to work (DARN, SCV), so there are feature bits for | |||||
| // those as well. The minimum processor requirement is POWER8 (ISA 2.07). | |||||
| // The struct is padded to avoid false sharing. | |||||
| var PPC64 struct { | |||||
| _ CacheLinePad | |||||
| HasDARN bool // Hardware random number generator (requires kernel enablement) | |||||
| HasSCV bool // Syscall vectored (requires kernel enablement) | |||||
| IsPOWER8 bool // ISA v2.07 (POWER8) | |||||
| IsPOWER9 bool // ISA v3.00 (POWER9) | |||||
| _ CacheLinePad | |||||
| } | |||||
| // S390X contains the supported CPU features of the current IBM Z | |||||
| // (s390x) platform. If the current platform is not IBM Z then all | |||||
| // feature flags are false. | |||||
| // | |||||
| // S390X is padded to avoid false sharing. Further HasVX is only set | |||||
| // if the OS supports vector registers in addition to the STFLE | |||||
| // feature bit being set. | |||||
| var S390X struct { | |||||
| _ CacheLinePad | |||||
| HasZARCH bool // z/Architecture mode is active [mandatory] | |||||
| HasSTFLE bool // store facility list extended | |||||
| HasLDISP bool // long (20-bit) displacements | |||||
| HasEIMM bool // 32-bit immediates | |||||
| HasDFP bool // decimal floating point | |||||
| HasETF3EH bool // ETF-3 enhanced | |||||
| HasMSA bool // message security assist (CPACF) | |||||
| HasAES bool // KM-AES{128,192,256} functions | |||||
| HasAESCBC bool // KMC-AES{128,192,256} functions | |||||
| HasAESCTR bool // KMCTR-AES{128,192,256} functions | |||||
| HasAESGCM bool // KMA-GCM-AES{128,192,256} functions | |||||
| HasGHASH bool // KIMD-GHASH function | |||||
| HasSHA1 bool // K{I,L}MD-SHA-1 functions | |||||
| HasSHA256 bool // K{I,L}MD-SHA-256 functions | |||||
| HasSHA512 bool // K{I,L}MD-SHA-512 functions | |||||
| HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions | |||||
| HasVX bool // vector facility | |||||
| HasVXE bool // vector-enhancements facility 1 | |||||
| _ CacheLinePad | |||||
| } | |||||
| @@ -0,0 +1,30 @@ | |||||
| // 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. | |||||
| // +build aix,ppc64 | |||||
| package cpu | |||||
| import "golang.org/x/sys/unix" | |||||
| const cacheLineSize = 128 | |||||
| const ( | |||||
| // getsystemcfg constants | |||||
| _SC_IMPL = 2 | |||||
| _IMPL_POWER8 = 0x10000 | |||||
| _IMPL_POWER9 = 0x20000 | |||||
| ) | |||||
| func init() { | |||||
| impl := unix.Getsystemcfg(_SC_IMPL) | |||||
| if impl&_IMPL_POWER8 != 0 { | |||||
| PPC64.IsPOWER8 = true | |||||
| } | |||||
| if impl&_IMPL_POWER9 != 0 { | |||||
| PPC64.IsPOWER9 = true | |||||
| } | |||||
| Initialized = true | |||||
| } | |||||
| @@ -0,0 +1,9 @@ | |||||
| // Copyright 2018 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. | |||||
| package cpu | |||||
| const cacheLineSize = 32 | |||||
| func doinit() {} | |||||
| @@ -0,0 +1,21 @@ | |||||
| // 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. | |||||
| // +build !gccgo | |||||
| package cpu | |||||
| // haveAsmFunctions reports whether the other functions in this file can | |||||
| // be safely called. | |||||
| func haveAsmFunctions() bool { return true } | |||||
| // The following feature detection functions are defined in cpu_s390x.s. | |||||
| // They are likely to be expensive to call so the results should be cached. | |||||
| func stfle() facilityList | |||||
| func kmQuery() queryResult | |||||
| func kmcQuery() queryResult | |||||
| func kmctrQuery() queryResult | |||||
| func kmaQuery() queryResult | |||||
| func kimdQuery() queryResult | |||||
| func klmdQuery() queryResult | |||||
| @@ -0,0 +1,16 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build 386 amd64 amd64p32 | |||||
| // +build !gccgo | |||||
| package cpu | |||||
| // cpuid is implemented in cpu_x86.s for gc compiler | |||||
| // and in cpu_gccgo.c for gccgo. | |||||
| func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) | |||||
| // xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler | |||||
| // and in cpu_gccgo.c for gccgo. | |||||
| func xgetbv() (eax, edx uint32) | |||||
| @@ -0,0 +1,43 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build 386 amd64 amd64p32 | |||||
| // +build gccgo | |||||
| #include <cpuid.h> | |||||
| #include <stdint.h> | |||||
| // Need to wrap __get_cpuid_count because it's declared as static. | |||||
| int | |||||
| gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf, | |||||
| uint32_t *eax, uint32_t *ebx, | |||||
| uint32_t *ecx, uint32_t *edx) | |||||
| { | |||||
| return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx); | |||||
| } | |||||
| // xgetbv reads the contents of an XCR (Extended Control Register) | |||||
| // specified in the ECX register into registers EDX:EAX. | |||||
| // Currently, the only supported value for XCR is 0. | |||||
| // | |||||
| // TODO: Replace with a better alternative: | |||||
| // | |||||
| // #include <xsaveintrin.h> | |||||
| // | |||||
| // #pragma GCC target("xsave") | |||||
| // | |||||
| // void gccgoXgetbv(uint32_t *eax, uint32_t *edx) { | |||||
| // unsigned long long x = _xgetbv(0); | |||||
| // *eax = x & 0xffffffff; | |||||
| // *edx = (x >> 32) & 0xffffffff; | |||||
| // } | |||||
| // | |||||
| // Note that _xgetbv is defined starting with GCC 8. | |||||
| void | |||||
| gccgoXgetbv(uint32_t *eax, uint32_t *edx) | |||||
| { | |||||
| __asm(" xorl %%ecx, %%ecx\n" | |||||
| " xgetbv" | |||||
| : "=a"(*eax), "=d"(*edx)); | |||||
| } | |||||
| @@ -0,0 +1,26 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build 386 amd64 amd64p32 | |||||
| // +build gccgo | |||||
| package cpu | |||||
| //extern gccgoGetCpuidCount | |||||
| func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32) | |||||
| func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) { | |||||
| var a, b, c, d uint32 | |||||
| gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d) | |||||
| return a, b, c, d | |||||
| } | |||||
| //extern gccgoXgetbv | |||||
| func gccgoXgetbv(eax, edx *uint32) | |||||
| func xgetbv() (eax, edx uint32) { | |||||
| var a, d uint32 | |||||
| gccgoXgetbv(&a, &d) | |||||
| return a, d | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| // 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. | |||||
| // +build gccgo | |||||
| package cpu | |||||
| // haveAsmFunctions reports whether the other functions in this file can | |||||
| // be safely called. | |||||
| func haveAsmFunctions() bool { return false } | |||||
| // TODO(mundaym): the following feature detection functions are currently | |||||
| // stubs. See https://golang.org/cl/162887 for how to fix this. | |||||
| // They are likely to be expensive to call so the results should be cached. | |||||
| func stfle() facilityList { panic("not implemented for gccgo") } | |||||
| func kmQuery() queryResult { panic("not implemented for gccgo") } | |||||
| func kmcQuery() queryResult { panic("not implemented for gccgo") } | |||||
| func kmctrQuery() queryResult { panic("not implemented for gccgo") } | |||||
| func kmaQuery() queryResult { panic("not implemented for gccgo") } | |||||
| func kimdQuery() queryResult { panic("not implemented for gccgo") } | |||||
| func klmdQuery() queryResult { panic("not implemented for gccgo") } | |||||
| @@ -0,0 +1,59 @@ | |||||
| // Copyright 2018 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. | |||||
| //+build !amd64,!amd64p32,!386 | |||||
| package cpu | |||||
| import ( | |||||
| "io/ioutil" | |||||
| ) | |||||
| const ( | |||||
| _AT_HWCAP = 16 | |||||
| _AT_HWCAP2 = 26 | |||||
| procAuxv = "/proc/self/auxv" | |||||
| uintSize = int(32 << (^uint(0) >> 63)) | |||||
| ) | |||||
| // For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 | |||||
| // These are initialized in cpu_$GOARCH.go | |||||
| // and should not be changed after they are initialized. | |||||
| var hwCap uint | |||||
| var hwCap2 uint | |||||
| func init() { | |||||
| buf, err := ioutil.ReadFile(procAuxv) | |||||
| if err != nil { | |||||
| // e.g. on android /proc/self/auxv is not accessible, so silently | |||||
| // ignore the error and leave Initialized = false | |||||
| return | |||||
| } | |||||
| bo := hostByteOrder() | |||||
| for len(buf) >= 2*(uintSize/8) { | |||||
| var tag, val uint | |||||
| switch uintSize { | |||||
| case 32: | |||||
| tag = uint(bo.Uint32(buf[0:])) | |||||
| val = uint(bo.Uint32(buf[4:])) | |||||
| buf = buf[8:] | |||||
| case 64: | |||||
| tag = uint(bo.Uint64(buf[0:])) | |||||
| val = uint(bo.Uint64(buf[8:])) | |||||
| buf = buf[16:] | |||||
| } | |||||
| switch tag { | |||||
| case _AT_HWCAP: | |||||
| hwCap = val | |||||
| case _AT_HWCAP2: | |||||
| hwCap2 = val | |||||
| } | |||||
| } | |||||
| doinit() | |||||
| Initialized = true | |||||
| } | |||||
| @@ -0,0 +1,67 @@ | |||||
| // Copyright 2018 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. | |||||
| package cpu | |||||
| const cacheLineSize = 64 | |||||
| // HWCAP/HWCAP2 bits. These are exposed by Linux. | |||||
| const ( | |||||
| hwcap_FP = 1 << 0 | |||||
| hwcap_ASIMD = 1 << 1 | |||||
| hwcap_EVTSTRM = 1 << 2 | |||||
| hwcap_AES = 1 << 3 | |||||
| hwcap_PMULL = 1 << 4 | |||||
| hwcap_SHA1 = 1 << 5 | |||||
| hwcap_SHA2 = 1 << 6 | |||||
| hwcap_CRC32 = 1 << 7 | |||||
| hwcap_ATOMICS = 1 << 8 | |||||
| hwcap_FPHP = 1 << 9 | |||||
| hwcap_ASIMDHP = 1 << 10 | |||||
| hwcap_CPUID = 1 << 11 | |||||
| hwcap_ASIMDRDM = 1 << 12 | |||||
| hwcap_JSCVT = 1 << 13 | |||||
| hwcap_FCMA = 1 << 14 | |||||
| hwcap_LRCPC = 1 << 15 | |||||
| hwcap_DCPOP = 1 << 16 | |||||
| hwcap_SHA3 = 1 << 17 | |||||
| hwcap_SM3 = 1 << 18 | |||||
| hwcap_SM4 = 1 << 19 | |||||
| hwcap_ASIMDDP = 1 << 20 | |||||
| hwcap_SHA512 = 1 << 21 | |||||
| hwcap_SVE = 1 << 22 | |||||
| hwcap_ASIMDFHM = 1 << 23 | |||||
| ) | |||||
| func doinit() { | |||||
| // HWCAP feature bits | |||||
| ARM64.HasFP = isSet(hwCap, hwcap_FP) | |||||
| ARM64.HasASIMD = isSet(hwCap, hwcap_ASIMD) | |||||
| ARM64.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM) | |||||
| ARM64.HasAES = isSet(hwCap, hwcap_AES) | |||||
| ARM64.HasPMULL = isSet(hwCap, hwcap_PMULL) | |||||
| ARM64.HasSHA1 = isSet(hwCap, hwcap_SHA1) | |||||
| ARM64.HasSHA2 = isSet(hwCap, hwcap_SHA2) | |||||
| ARM64.HasCRC32 = isSet(hwCap, hwcap_CRC32) | |||||
| ARM64.HasATOMICS = isSet(hwCap, hwcap_ATOMICS) | |||||
| ARM64.HasFPHP = isSet(hwCap, hwcap_FPHP) | |||||
| ARM64.HasASIMDHP = isSet(hwCap, hwcap_ASIMDHP) | |||||
| ARM64.HasCPUID = isSet(hwCap, hwcap_CPUID) | |||||
| ARM64.HasASIMDRDM = isSet(hwCap, hwcap_ASIMDRDM) | |||||
| ARM64.HasJSCVT = isSet(hwCap, hwcap_JSCVT) | |||||
| ARM64.HasFCMA = isSet(hwCap, hwcap_FCMA) | |||||
| ARM64.HasLRCPC = isSet(hwCap, hwcap_LRCPC) | |||||
| ARM64.HasDCPOP = isSet(hwCap, hwcap_DCPOP) | |||||
| ARM64.HasSHA3 = isSet(hwCap, hwcap_SHA3) | |||||
| ARM64.HasSM3 = isSet(hwCap, hwcap_SM3) | |||||
| ARM64.HasSM4 = isSet(hwCap, hwcap_SM4) | |||||
| ARM64.HasASIMDDP = isSet(hwCap, hwcap_ASIMDDP) | |||||
| ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) | |||||
| ARM64.HasSVE = isSet(hwCap, hwcap_SVE) | |||||
| ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) | |||||
| } | |||||
| func isSet(hwc uint, value uint) bool { | |||||
| return hwc&value != 0 | |||||
| } | |||||
| @@ -0,0 +1,33 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build linux | |||||
| // +build ppc64 ppc64le | |||||
| package cpu | |||||
| const cacheLineSize = 128 | |||||
| // HWCAP/HWCAP2 bits. These are exposed by the kernel. | |||||
| const ( | |||||
| // ISA Level | |||||
| _PPC_FEATURE2_ARCH_2_07 = 0x80000000 | |||||
| _PPC_FEATURE2_ARCH_3_00 = 0x00800000 | |||||
| // CPU features | |||||
| _PPC_FEATURE2_DARN = 0x00200000 | |||||
| _PPC_FEATURE2_SCV = 0x00100000 | |||||
| ) | |||||
| func doinit() { | |||||
| // HWCAP2 feature bits | |||||
| PPC64.IsPOWER8 = isSet(hwCap2, _PPC_FEATURE2_ARCH_2_07) | |||||
| PPC64.IsPOWER9 = isSet(hwCap2, _PPC_FEATURE2_ARCH_3_00) | |||||
| PPC64.HasDARN = isSet(hwCap2, _PPC_FEATURE2_DARN) | |||||
| PPC64.HasSCV = isSet(hwCap2, _PPC_FEATURE2_SCV) | |||||
| } | |||||
| func isSet(hwc uint, value uint) bool { | |||||
| return hwc&value != 0 | |||||
| } | |||||
| @@ -0,0 +1,161 @@ | |||||
| // 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. | |||||
| package cpu | |||||
| const cacheLineSize = 256 | |||||
| const ( | |||||
| // bit mask values from /usr/include/bits/hwcap.h | |||||
| hwcap_ZARCH = 2 | |||||
| hwcap_STFLE = 4 | |||||
| hwcap_MSA = 8 | |||||
| hwcap_LDISP = 16 | |||||
| hwcap_EIMM = 32 | |||||
| hwcap_DFP = 64 | |||||
| hwcap_ETF3EH = 256 | |||||
| hwcap_VX = 2048 | |||||
| hwcap_VXE = 8192 | |||||
| ) | |||||
| // bitIsSet reports whether the bit at index is set. The bit index | |||||
| // is in big endian order, so bit index 0 is the leftmost bit. | |||||
| func bitIsSet(bits []uint64, index uint) bool { | |||||
| return bits[index/64]&((1<<63)>>(index%64)) != 0 | |||||
| } | |||||
| // function is the code for the named cryptographic function. | |||||
| type function uint8 | |||||
| const ( | |||||
| // KM{,A,C,CTR} function codes | |||||
| aes128 function = 18 // AES-128 | |||||
| aes192 function = 19 // AES-192 | |||||
| aes256 function = 20 // AES-256 | |||||
| // K{I,L}MD function codes | |||||
| sha1 function = 1 // SHA-1 | |||||
| sha256 function = 2 // SHA-256 | |||||
| sha512 function = 3 // SHA-512 | |||||
| sha3_224 function = 32 // SHA3-224 | |||||
| sha3_256 function = 33 // SHA3-256 | |||||
| sha3_384 function = 34 // SHA3-384 | |||||
| sha3_512 function = 35 // SHA3-512 | |||||
| shake128 function = 36 // SHAKE-128 | |||||
| shake256 function = 37 // SHAKE-256 | |||||
| // KLMD function codes | |||||
| ghash function = 65 // GHASH | |||||
| ) | |||||
| // queryResult contains the result of a Query function | |||||
| // call. Bits are numbered in big endian order so the | |||||
| // leftmost bit (the MSB) is at index 0. | |||||
| type queryResult struct { | |||||
| bits [2]uint64 | |||||
| } | |||||
| // Has reports whether the given functions are present. | |||||
| func (q *queryResult) Has(fns ...function) bool { | |||||
| if len(fns) == 0 { | |||||
| panic("no function codes provided") | |||||
| } | |||||
| for _, f := range fns { | |||||
| if !bitIsSet(q.bits[:], uint(f)) { | |||||
| return false | |||||
| } | |||||
| } | |||||
| return true | |||||
| } | |||||
| // facility is a bit index for the named facility. | |||||
| type facility uint8 | |||||
| const ( | |||||
| // cryptography facilities | |||||
| msa4 facility = 77 // message-security-assist extension 4 | |||||
| msa8 facility = 146 // message-security-assist extension 8 | |||||
| ) | |||||
| // facilityList contains the result of an STFLE call. | |||||
| // Bits are numbered in big endian order so the | |||||
| // leftmost bit (the MSB) is at index 0. | |||||
| type facilityList struct { | |||||
| bits [4]uint64 | |||||
| } | |||||
| // Has reports whether the given facilities are present. | |||||
| func (s *facilityList) Has(fs ...facility) bool { | |||||
| if len(fs) == 0 { | |||||
| panic("no facility bits provided") | |||||
| } | |||||
| for _, f := range fs { | |||||
| if !bitIsSet(s.bits[:], uint(f)) { | |||||
| return false | |||||
| } | |||||
| } | |||||
| return true | |||||
| } | |||||
| func doinit() { | |||||
| // test HWCAP bit vector | |||||
| has := func(featureMask uint) bool { | |||||
| return hwCap&featureMask == featureMask | |||||
| } | |||||
| // mandatory | |||||
| S390X.HasZARCH = has(hwcap_ZARCH) | |||||
| // optional | |||||
| S390X.HasSTFLE = has(hwcap_STFLE) | |||||
| S390X.HasLDISP = has(hwcap_LDISP) | |||||
| S390X.HasEIMM = has(hwcap_EIMM) | |||||
| S390X.HasETF3EH = has(hwcap_ETF3EH) | |||||
| S390X.HasDFP = has(hwcap_DFP) | |||||
| S390X.HasMSA = has(hwcap_MSA) | |||||
| S390X.HasVX = has(hwcap_VX) | |||||
| if S390X.HasVX { | |||||
| S390X.HasVXE = has(hwcap_VXE) | |||||
| } | |||||
| // We need implementations of stfle, km and so on | |||||
| // to detect cryptographic features. | |||||
| if !haveAsmFunctions() { | |||||
| return | |||||
| } | |||||
| // optional cryptographic functions | |||||
| if S390X.HasMSA { | |||||
| aes := []function{aes128, aes192, aes256} | |||||
| // cipher message | |||||
| km, kmc := kmQuery(), kmcQuery() | |||||
| S390X.HasAES = km.Has(aes...) | |||||
| S390X.HasAESCBC = kmc.Has(aes...) | |||||
| if S390X.HasSTFLE { | |||||
| facilities := stfle() | |||||
| if facilities.Has(msa4) { | |||||
| kmctr := kmctrQuery() | |||||
| S390X.HasAESCTR = kmctr.Has(aes...) | |||||
| } | |||||
| if facilities.Has(msa8) { | |||||
| kma := kmaQuery() | |||||
| S390X.HasAESGCM = kma.Has(aes...) | |||||
| } | |||||
| } | |||||
| // compute message digest | |||||
| kimd := kimdQuery() // intermediate (no padding) | |||||
| klmd := klmdQuery() // last (padding) | |||||
| S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) | |||||
| S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) | |||||
| S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) | |||||
| S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist | |||||
| sha3 := []function{ | |||||
| sha3_224, sha3_256, sha3_384, sha3_512, | |||||
| shake128, shake256, | |||||
| } | |||||
| S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build mips64 mips64le | |||||
| package cpu | |||||
| const cacheLineSize = 32 | |||||
| func doinit() {} | |||||
| @@ -0,0 +1,11 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build mips mipsle | |||||
| package cpu | |||||
| const cacheLineSize = 32 | |||||
| func doinit() {} | |||||
| @@ -0,0 +1,11 @@ | |||||
| // 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. | |||||
| // +build !linux,arm64 | |||||
| package cpu | |||||
| const cacheLineSize = 64 | |||||
| func doinit() {} | |||||
| @@ -0,0 +1,57 @@ | |||||
| // 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. | |||||
| // +build !gccgo | |||||
| #include "textflag.h" | |||||
| // func stfle() facilityList | |||||
| TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 | |||||
| MOVD $ret+0(FP), R1 | |||||
| MOVD $3, R0 // last doubleword index to store | |||||
| XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) | |||||
| WORD $0xb2b01000 // store facility list extended (STFLE) | |||||
| RET | |||||
| // func kmQuery() queryResult | |||||
| TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 | |||||
| MOVD $0, R0 // set function code to 0 (KM-Query) | |||||
| MOVD $ret+0(FP), R1 // address of 16-byte return value | |||||
| WORD $0xB92E0024 // cipher message (KM) | |||||
| RET | |||||
| // func kmcQuery() queryResult | |||||
| TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 | |||||
| MOVD $0, R0 // set function code to 0 (KMC-Query) | |||||
| MOVD $ret+0(FP), R1 // address of 16-byte return value | |||||
| WORD $0xB92F0024 // cipher message with chaining (KMC) | |||||
| RET | |||||
| // func kmctrQuery() queryResult | |||||
| TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 | |||||
| MOVD $0, R0 // set function code to 0 (KMCTR-Query) | |||||
| MOVD $ret+0(FP), R1 // address of 16-byte return value | |||||
| WORD $0xB92D4024 // cipher message with counter (KMCTR) | |||||
| RET | |||||
| // func kmaQuery() queryResult | |||||
| TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 | |||||
| MOVD $0, R0 // set function code to 0 (KMA-Query) | |||||
| MOVD $ret+0(FP), R1 // address of 16-byte return value | |||||
| WORD $0xb9296024 // cipher message with authentication (KMA) | |||||
| RET | |||||
| // func kimdQuery() queryResult | |||||
| TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 | |||||
| MOVD $0, R0 // set function code to 0 (KIMD-Query) | |||||
| MOVD $ret+0(FP), R1 // address of 16-byte return value | |||||
| WORD $0xB93E0024 // compute intermediate message digest (KIMD) | |||||
| RET | |||||
| // func klmdQuery() queryResult | |||||
| TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 | |||||
| MOVD $0, R0 // set function code to 0 (KLMD-Query) | |||||
| MOVD $ret+0(FP), R1 // address of 16-byte return value | |||||
| WORD $0xB93F0024 // compute last message digest (KLMD) | |||||
| RET | |||||
| @@ -0,0 +1,15 @@ | |||||
| // 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. | |||||
| // +build wasm | |||||
| package cpu | |||||
| // We're compiling the cpu package for an unknown (software-abstracted) CPU. | |||||
| // Make CacheLinePad an empty struct and hope that the usual struct alignment | |||||
| // rules are good enough. | |||||
| const cacheLineSize = 0 | |||||
| func doinit() {} | |||||
| @@ -0,0 +1,59 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build 386 amd64 amd64p32 | |||||
| package cpu | |||||
| const cacheLineSize = 64 | |||||
| func init() { | |||||
| Initialized = true | |||||
| maxID, _, _, _ := cpuid(0, 0) | |||||
| if maxID < 1 { | |||||
| return | |||||
| } | |||||
| _, _, ecx1, edx1 := cpuid(1, 0) | |||||
| X86.HasSSE2 = isSet(26, edx1) | |||||
| X86.HasSSE3 = isSet(0, ecx1) | |||||
| X86.HasPCLMULQDQ = isSet(1, ecx1) | |||||
| X86.HasSSSE3 = isSet(9, ecx1) | |||||
| X86.HasFMA = isSet(12, ecx1) | |||||
| X86.HasSSE41 = isSet(19, ecx1) | |||||
| X86.HasSSE42 = isSet(20, ecx1) | |||||
| X86.HasPOPCNT = isSet(23, ecx1) | |||||
| X86.HasAES = isSet(25, ecx1) | |||||
| X86.HasOSXSAVE = isSet(27, ecx1) | |||||
| X86.HasRDRAND = isSet(30, ecx1) | |||||
| osSupportsAVX := false | |||||
| // For XGETBV, OSXSAVE bit is required and sufficient. | |||||
| if X86.HasOSXSAVE { | |||||
| eax, _ := xgetbv() | |||||
| // Check if XMM and YMM registers have OS support. | |||||
| osSupportsAVX = isSet(1, eax) && isSet(2, eax) | |||||
| } | |||||
| X86.HasAVX = isSet(28, ecx1) && osSupportsAVX | |||||
| if maxID < 7 { | |||||
| return | |||||
| } | |||||
| _, ebx7, _, _ := cpuid(7, 0) | |||||
| X86.HasBMI1 = isSet(3, ebx7) | |||||
| X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX | |||||
| X86.HasBMI2 = isSet(8, ebx7) | |||||
| X86.HasERMS = isSet(9, ebx7) | |||||
| X86.HasRDSEED = isSet(18, ebx7) | |||||
| X86.HasADX = isSet(19, ebx7) | |||||
| } | |||||
| func isSet(bitpos uint, value uint32) bool { | |||||
| return value&(1<<bitpos) != 0 | |||||
| } | |||||
| @@ -0,0 +1,27 @@ | |||||
| // Copyright 2018 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. | |||||
| // +build 386 amd64 amd64p32 | |||||
| // +build !gccgo | |||||
| #include "textflag.h" | |||||
| // func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) | |||||
| TEXT ·cpuid(SB), NOSPLIT, $0-24 | |||||
| MOVL eaxArg+0(FP), AX | |||||
| MOVL ecxArg+4(FP), CX | |||||
| CPUID | |||||
| MOVL AX, eax+8(FP) | |||||
| MOVL BX, ebx+12(FP) | |||||
| MOVL CX, ecx+16(FP) | |||||
| MOVL DX, edx+20(FP) | |||||
| RET | |||||
| // func xgetbv() (eax, edx uint32) | |||||
| TEXT ·xgetbv(SB),NOSPLIT,$0-8 | |||||
| MOVL $0, CX | |||||
| XGETBV | |||||
| MOVL AX, eax+0(FP) | |||||
| MOVL DX, edx+4(FP) | |||||
| RET | |||||
| @@ -207,8 +207,6 @@ esac | |||||
| esac | esac | ||||
| if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi | if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi | ||||
| if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi | if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi | ||||
| if [ -n "$mktypes" ]; then | |||||
| echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; | |||||
| if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi | |||||
| if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi | if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi | ||||
| fi | |||||
| ) | $run | ) | $run | ||||
| @@ -192,6 +192,7 @@ struct ltchars { | |||||
| #include <linux/if_packet.h> | #include <linux/if_packet.h> | ||||
| #include <linux/if_addr.h> | #include <linux/if_addr.h> | ||||
| #include <linux/falloc.h> | #include <linux/falloc.h> | ||||
| #include <linux/fanotify.h> | |||||
| #include <linux/filter.h> | #include <linux/filter.h> | ||||
| #include <linux/fs.h> | #include <linux/fs.h> | ||||
| #include <linux/kexec.h> | #include <linux/kexec.h> | ||||
| @@ -501,6 +502,7 @@ ccflags="$@" | |||||
| $2 !~ "WMESGLEN" && | $2 !~ "WMESGLEN" && | ||||
| $2 ~ /^W[A-Z0-9]+$/ || | $2 ~ /^W[A-Z0-9]+$/ || | ||||
| $2 ~/^PPPIOC/ || | $2 ~/^PPPIOC/ || | ||||
| $2 ~ /^FAN_|FANOTIFY_/ || | |||||
| $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} | $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} | ||||
| $2 ~ /^__WCOREFLAG$/ {next} | $2 ~ /^__WCOREFLAG$/ {next} | ||||
| $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} | $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} | ||||
| @@ -153,6 +153,11 @@ func main() { | |||||
| } | } | ||||
| funct, inps, outps, sysname := f[2], f[3], f[4], f[5] | funct, inps, outps, sysname := f[2], f[3], f[4], f[5] | ||||
| // ClockGettime doesn't have a syscall number on Darwin, only generate libc wrappers. | |||||
| if goos == "darwin" && !libc && funct == "ClockGettime" { | |||||
| continue | |||||
| } | |||||
| // Split argument lists on comma. | // Split argument lists on comma. | ||||
| in := parseParamList(inps) | in := parseParamList(inps) | ||||
| out := parseParamList(outps) | out := parseParamList(outps) | ||||
| @@ -228,7 +233,7 @@ func main() { | |||||
| } else { | } else { | ||||
| args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) | args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| } | } | ||||
| } else if p.Type == "int64" && endianness != "" { | |||||
| } else if (p.Type == "int64" || p.Type == "uint64") && endianness != "" { | |||||
| if len(args)%2 == 1 && *arm { | if len(args)%2 == 1 && *arm { | ||||
| // arm abi specifies 64-bit argument uses | // arm abi specifies 64-bit argument uses | ||||
| // (even, odd) pair | // (even, odd) pair | ||||
| @@ -25,8 +25,8 @@ func cmsgAlignOf(salen int) int { | |||||
| if SizeofPtr == 8 { | if SizeofPtr == 8 { | ||||
| salign = 4 | salign = 4 | ||||
| } | } | ||||
| case "openbsd": | |||||
| // OpenBSD armv7 requires 64-bit alignment. | |||||
| case "netbsd", "openbsd": | |||||
| // NetBSD and OpenBSD armv7 require 64-bit alignment. | |||||
| if runtime.GOARCH == "arm" { | if runtime.GOARCH == "arm" { | ||||
| salign = 8 | salign = 8 | ||||
| } | } | ||||
| @@ -545,3 +545,5 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { | |||||
| //sys gettimeofday(tv *Timeval, tzp *Timezone) (err error) | //sys gettimeofday(tv *Timeval, tzp *Timezone) (err error) | ||||
| //sysnb Time(t *Time_t) (tt Time_t, err error) | //sysnb Time(t *Time_t) (tt Time_t, err error) | ||||
| //sys Utime(path string, buf *Utimbuf) (err error) | //sys Utime(path string, buf *Utimbuf) (err error) | ||||
| //sys Getsystemcfg(label int) (n uint64) | |||||
| @@ -144,6 +144,23 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) ( | |||||
| //sys getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) | //sys getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error) | ||||
| func SysctlClockinfo(name string) (*Clockinfo, error) { | |||||
| mib, err := sysctlmib(name) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| n := uintptr(SizeofClockinfo) | |||||
| var ci Clockinfo | |||||
| if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if n != SizeofClockinfo { | |||||
| return nil, EIO | |||||
| } | |||||
| return &ci, nil | |||||
| } | |||||
| //sysnb pipe() (r int, w int, err error) | //sysnb pipe() (r int, w int, err error) | ||||
| func Pipe(p []int) (err error) { | func Pipe(p []int) (err error) { | ||||
| @@ -39,6 +39,20 @@ func Creat(path string, mode uint32) (fd int, err error) { | |||||
| return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) | return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) | ||||
| } | } | ||||
| //sys FanotifyInit(flags uint, event_f_flags uint) (fd int, err error) | |||||
| //sys fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error) | |||||
| func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) (err error) { | |||||
| if pathname == "" { | |||||
| return fanotifyMark(fd, flags, mask, dirFd, nil) | |||||
| } | |||||
| p, err := BytePtrFromString(pathname) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| return fanotifyMark(fd, flags, mask, dirFd, p) | |||||
| } | |||||
| //sys fchmodat(dirfd int, path string, mode uint32) (err error) | //sys fchmodat(dirfd int, path string, mode uint32) (err error) | ||||
| func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { | func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { | ||||
| @@ -990,10 +1004,28 @@ func GetsockoptString(fd, level, opt int) (string, error) { | |||||
| return string(buf[:vallen-1]), nil | return string(buf[:vallen-1]), nil | ||||
| } | } | ||||
| func GetsockoptTpacketStats(fd, level, opt int) (*TpacketStats, error) { | |||||
| var value TpacketStats | |||||
| vallen := _Socklen(SizeofTpacketStats) | |||||
| err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) | |||||
| return &value, err | |||||
| } | |||||
| func GetsockoptTpacketStatsV3(fd, level, opt int) (*TpacketStatsV3, error) { | |||||
| var value TpacketStatsV3 | |||||
| vallen := _Socklen(SizeofTpacketStatsV3) | |||||
| err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) | |||||
| return &value, err | |||||
| } | |||||
| func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { | func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { | ||||
| return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) | return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) | ||||
| } | } | ||||
| func SetsockoptPacketMreq(fd, level, opt int, mreq *PacketMreq) error { | |||||
| return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) | |||||
| } | |||||
| // SetsockoptSockFprog attaches a classic BPF or an extended BPF program to a | // SetsockoptSockFprog attaches a classic BPF or an extended BPF program to a | ||||
| // socket to filter incoming packets. See 'man 7 socket' for usage information. | // socket to filter incoming packets. See 'man 7 socket' for usage information. | ||||
| func SetsockoptSockFprog(fd, level, opt int, fprog *SockFprog) error { | func SetsockoptSockFprog(fd, level, opt int, fprog *SockFprog) error { | ||||
| @@ -1008,6 +1040,14 @@ func SetsockoptCanRawFilter(fd, level, opt int, filter []CanFilter) error { | |||||
| return setsockopt(fd, level, opt, p, uintptr(len(filter)*SizeofCanFilter)) | return setsockopt(fd, level, opt, p, uintptr(len(filter)*SizeofCanFilter)) | ||||
| } | } | ||||
| func SetsockoptTpacketReq(fd, level, opt int, tp *TpacketReq) error { | |||||
| return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp)) | |||||
| } | |||||
| func SetsockoptTpacketReq3(fd, level, opt int, tp *TpacketReq3) error { | |||||
| return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp)) | |||||
| } | |||||
| // Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html) | // Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html) | ||||
| // KeyctlInt calls keyctl commands in which each argument is an int. | // KeyctlInt calls keyctl commands in which each argument is an int. | ||||
| @@ -19,12 +19,18 @@ func setTimeval(sec, usec int64) Timeval { | |||||
| return Timeval{Sec: int32(sec), Usec: int32(usec)} | return Timeval{Sec: int32(sec), Usec: int32(usec)} | ||||
| } | } | ||||
| //sysnb pipe(p *[2]_C_int) (err error) | |||||
| func Pipe(p []int) (err error) { | func Pipe(p []int) (err error) { | ||||
| if len(p) != 2 { | if len(p) != 2 { | ||||
| return EINVAL | return EINVAL | ||||
| } | } | ||||
| var pp [2]_C_int | var pp [2]_C_int | ||||
| // Try pipe2 first for Android O, then try pipe for kernel 2.6.23. | |||||
| err = pipe2(&pp, 0) | err = pipe2(&pp, 0) | ||||
| if err == ENOSYS { | |||||
| err = pipe(&pp) | |||||
| } | |||||
| p[0] = int(pp[0]) | p[0] = int(pp[0]) | ||||
| p[1] = int(pp[1]) | p[1] = int(pp[1]) | ||||
| return | return | ||||
| @@ -208,3 +208,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { | |||||
| } | } | ||||
| return ppoll(&fds[0], len(fds), ts, nil) | return ppoll(&fds[0], len(fds), ts, nil) | ||||
| } | } | ||||
| //sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) | |||||
| func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { | |||||
| cmdlineLen := len(cmdline) | |||||
| if cmdlineLen > 0 { | |||||
| // Account for the additional NULL byte added by | |||||
| // BytePtrFromString in kexecFileLoad. The kexec_file_load | |||||
| // syscall expects a NULL-terminated string. | |||||
| cmdlineLen++ | |||||
| } | |||||
| return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) | |||||
| } | |||||
| @@ -211,3 +211,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { | |||||
| func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { | func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { | ||||
| return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0) | return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0) | ||||
| } | } | ||||
| //sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error) | |||||
| func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error { | |||||
| cmdlineLen := len(cmdline) | |||||
| if cmdlineLen > 0 { | |||||
| // Account for the additional NULL byte added by | |||||
| // BytePtrFromString in kexecFileLoad. The kexec_file_load | |||||
| // syscall expects a NULL-terminated string. | |||||
| cmdlineLen++ | |||||
| } | |||||
| return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags) | |||||
| } | |||||
| @@ -43,6 +43,23 @@ func nametomib(name string) (mib []_C_int, err error) { | |||||
| return nil, EINVAL | return nil, EINVAL | ||||
| } | } | ||||
| func SysctlClockinfo(name string) (*Clockinfo, error) { | |||||
| mib, err := sysctlmib(name) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| n := uintptr(SizeofClockinfo) | |||||
| var ci Clockinfo | |||||
| if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| if n != SizeofClockinfo { | |||||
| return nil, EIO | |||||
| } | |||||
| return &ci, nil | |||||
| } | |||||
| func SysctlUvmexp(name string) (*Uvmexp, error) { | func SysctlUvmexp(name string) (*Uvmexp, error) { | ||||
| mib, err := sysctlmib(name) | mib, err := sysctlmib(name) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -28,6 +28,11 @@ var ( | |||||
| errENOENT error = syscall.ENOENT | errENOENT error = syscall.ENOENT | ||||
| ) | ) | ||||
| var ( | |||||
| signalNameMapOnce sync.Once | |||||
| signalNameMap map[string]syscall.Signal | |||||
| ) | |||||
| // errnoErr returns common boxed Errno values, to prevent | // errnoErr returns common boxed Errno values, to prevent | ||||
| // allocations at runtime. | // allocations at runtime. | ||||
| func errnoErr(e syscall.Errno) error { | func errnoErr(e syscall.Errno) error { | ||||
| @@ -66,6 +71,19 @@ func SignalName(s syscall.Signal) string { | |||||
| return "" | return "" | ||||
| } | } | ||||
| // SignalNum returns the syscall.Signal for signal named s, | |||||
| // or 0 if a signal with such name is not found. | |||||
| // The signal name should start with "SIG". | |||||
| func SignalNum(s string) syscall.Signal { | |||||
| signalNameMapOnce.Do(func() { | |||||
| signalNameMap = make(map[string]syscall.Signal) | |||||
| for _, signal := range signalList { | |||||
| signalNameMap[signal.name] = signal.num | |||||
| } | |||||
| }) | |||||
| return signalNameMap[s] | |||||
| } | |||||
| // clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte. | // clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte. | ||||
| func clen(n []byte) int { | func clen(n []byte) int { | ||||
| i := bytes.IndexByte(n, 0) | i := bytes.IndexByte(n, 0) | ||||
| @@ -276,6 +294,13 @@ func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) { | |||||
| return &tv, err | return &tv, err | ||||
| } | } | ||||
| func GetsockoptUint64(fd, level, opt int) (value uint64, err error) { | |||||
| var n uint64 | |||||
| vallen := _Socklen(8) | |||||
| err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen) | |||||
| return n, err | |||||
| } | |||||
| func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { | func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) { | ||||
| var rsa RawSockaddrAny | var rsa RawSockaddrAny | ||||
| var len _Socklen = SizeofSockaddrAny | var len _Socklen = SizeofSockaddrAny | ||||
| @@ -333,6 +358,10 @@ func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) { | |||||
| return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv)) | return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv)) | ||||
| } | } | ||||
| func SetsockoptUint64(fd, level, opt int, value uint64) (err error) { | |||||
| return setsockopt(fd, level, opt, unsafe.Pointer(&value), 8) | |||||
| } | |||||
| func Socket(domain, typ, proto int) (fd int, err error) { | func Socket(domain, typ, proto int) (fd int, err error) { | ||||
| if domain == AF_INET6 && SocketDisableIPv6 { | if domain == AF_INET6 && SocketDisableIPv6 { | ||||
| return -1, EAFNOSUPPORT | return -1, EAFNOSUPPORT | ||||
| @@ -377,3 +406,22 @@ func SetNonblock(fd int, nonblocking bool) (err error) { | |||||
| func Exec(argv0 string, argv []string, envv []string) error { | func Exec(argv0 string, argv []string, envv []string) error { | ||||
| return syscall.Exec(argv0, argv, envv) | return syscall.Exec(argv0, argv, envv) | ||||
| } | } | ||||
| // Lutimes sets the access and modification times tv on path. If path refers to | |||||
| // a symlink, it is not dereferenced and the timestamps are set on the symlink. | |||||
| // If tv is nil, the access and modification times are set to the current time. | |||||
| // Otherwise tv must contain exactly 2 elements, with access time as the first | |||||
| // element and modification time as the second element. | |||||
| func Lutimes(path string, tv []Timeval) error { | |||||
| if tv == nil { | |||||
| return UtimesNanoAt(AT_FDCWD, path, nil, AT_SYMLINK_NOFOLLOW) | |||||
| } | |||||
| if len(tv) != 2 { | |||||
| return EINVAL | |||||
| } | |||||
| ts := []Timespec{ | |||||
| NsecToTimespec(TimevalToNsec(tv[0])), | |||||
| NsecToTimespec(TimevalToNsec(tv[1])), | |||||
| } | |||||
| return UtimesNanoAt(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW) | |||||
| } | |||||
| @@ -275,3 +275,9 @@ const ( | |||||
| // uname | // uname | ||||
| type Utsname C.struct_utsname | type Utsname C.struct_utsname | ||||
| // Clockinfo | |||||
| const SizeofClockinfo = C.sizeof_struct_clockinfo | |||||
| type Clockinfo C.struct_clockinfo | |||||
| @@ -274,3 +274,9 @@ type Utsname C.struct_utsname | |||||
| const SizeofUvmexp = C.sizeof_struct_uvmexp | const SizeofUvmexp = C.sizeof_struct_uvmexp | ||||
| type Uvmexp C.struct_uvmexp | type Uvmexp C.struct_uvmexp | ||||
| // Clockinfo | |||||
| const SizeofClockinfo = C.sizeof_struct_clockinfo | |||||
| type Clockinfo C.struct_clockinfo | |||||
| @@ -174,6 +174,7 @@ const ( | |||||
| B9600 = 0xd | B9600 = 0xd | ||||
| BALLOON_KVM_MAGIC = 0x13661366 | BALLOON_KVM_MAGIC = 0x13661366 | ||||
| BDEVFS_MAGIC = 0x62646576 | BDEVFS_MAGIC = 0x62646576 | ||||
| BINDERFS_SUPER_MAGIC = 0x6c6f6f70 | |||||
| BINFMTFS_MAGIC = 0x42494e4d | BINFMTFS_MAGIC = 0x42494e4d | ||||
| BLKBSZGET = 0x80041270 | BLKBSZGET = 0x80041270 | ||||
| BLKBSZSET = 0x40041271 | BLKBSZSET = 0x40041271 | ||||
| @@ -486,6 +487,50 @@ const ( | |||||
| FALLOC_FL_PUNCH_HOLE = 0x2 | FALLOC_FL_PUNCH_HOLE = 0x2 | ||||
| FALLOC_FL_UNSHARE_RANGE = 0x40 | FALLOC_FL_UNSHARE_RANGE = 0x40 | ||||
| FALLOC_FL_ZERO_RANGE = 0x10 | FALLOC_FL_ZERO_RANGE = 0x10 | ||||
| FANOTIFY_METADATA_VERSION = 0x3 | |||||
| FAN_ACCESS = 0x1 | |||||
| FAN_ACCESS_PERM = 0x20000 | |||||
| FAN_ALLOW = 0x1 | |||||
| FAN_ALL_CLASS_BITS = 0xc | |||||
| FAN_ALL_EVENTS = 0x3b | |||||
| FAN_ALL_INIT_FLAGS = 0x3f | |||||
| FAN_ALL_MARK_FLAGS = 0xff | |||||
| FAN_ALL_OUTGOING_EVENTS = 0x3403b | |||||
| FAN_ALL_PERM_EVENTS = 0x30000 | |||||
| FAN_AUDIT = 0x10 | |||||
| FAN_CLASS_CONTENT = 0x4 | |||||
| FAN_CLASS_NOTIF = 0x0 | |||||
| FAN_CLASS_PRE_CONTENT = 0x8 | |||||
| FAN_CLOEXEC = 0x1 | |||||
| FAN_CLOSE = 0x18 | |||||
| FAN_CLOSE_NOWRITE = 0x10 | |||||
| FAN_CLOSE_WRITE = 0x8 | |||||
| FAN_DENY = 0x2 | |||||
| FAN_ENABLE_AUDIT = 0x40 | |||||
| FAN_EVENT_METADATA_LEN = 0x18 | |||||
| FAN_EVENT_ON_CHILD = 0x8000000 | |||||
| FAN_MARK_ADD = 0x1 | |||||
| FAN_MARK_DONT_FOLLOW = 0x4 | |||||
| FAN_MARK_FILESYSTEM = 0x100 | |||||
| FAN_MARK_FLUSH = 0x80 | |||||
| FAN_MARK_IGNORED_MASK = 0x20 | |||||
| FAN_MARK_IGNORED_SURV_MODIFY = 0x40 | |||||
| FAN_MARK_INODE = 0x0 | |||||
| FAN_MARK_MOUNT = 0x10 | |||||
| FAN_MARK_ONLYDIR = 0x8 | |||||
| FAN_MARK_REMOVE = 0x2 | |||||
| FAN_MODIFY = 0x2 | |||||
| FAN_NOFD = -0x1 | |||||
| FAN_NONBLOCK = 0x2 | |||||
| FAN_ONDIR = 0x40000000 | |||||
| FAN_OPEN = 0x20 | |||||
| FAN_OPEN_EXEC = 0x1000 | |||||
| FAN_OPEN_EXEC_PERM = 0x40000 | |||||
| FAN_OPEN_PERM = 0x10000 | |||||
| FAN_Q_OVERFLOW = 0x4000 | |||||
| FAN_REPORT_TID = 0x100 | |||||
| FAN_UNLIMITED_MARKS = 0x20 | |||||
| FAN_UNLIMITED_QUEUE = 0x10 | |||||
| FD_CLOEXEC = 0x1 | FD_CLOEXEC = 0x1 | ||||
| FD_SETSIZE = 0x400 | FD_SETSIZE = 0x400 | ||||
| FF0 = 0x0 | FF0 = 0x0 | ||||
| @@ -493,6 +538,7 @@ const ( | |||||
| FFDLY = 0x8000 | FFDLY = 0x8000 | ||||
| FLUSHO = 0x1000 | FLUSHO = 0x1000 | ||||
| FP_XSTATE_MAGIC2 = 0x46505845 | FP_XSTATE_MAGIC2 = 0x46505845 | ||||
| FS_ENCRYPTION_MODE_ADIANTUM = 0x9 | |||||
| FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 | FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 | ||||
| FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 | FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 | ||||
| FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 | FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 | ||||
| @@ -514,7 +560,7 @@ const ( | |||||
| FS_POLICY_FLAGS_PAD_4 = 0x0 | FS_POLICY_FLAGS_PAD_4 = 0x0 | ||||
| FS_POLICY_FLAGS_PAD_8 = 0x1 | FS_POLICY_FLAGS_PAD_8 = 0x1 | ||||
| FS_POLICY_FLAGS_PAD_MASK = 0x3 | FS_POLICY_FLAGS_PAD_MASK = 0x3 | ||||
| FS_POLICY_FLAGS_VALID = 0x3 | |||||
| FS_POLICY_FLAGS_VALID = 0x7 | |||||
| FUTEXFS_SUPER_MAGIC = 0xbad1dea | FUTEXFS_SUPER_MAGIC = 0xbad1dea | ||||
| F_ADD_SEALS = 0x409 | F_ADD_SEALS = 0x409 | ||||
| F_DUPFD = 0x0 | F_DUPFD = 0x0 | ||||
| @@ -1134,7 +1180,7 @@ const ( | |||||
| NETLINK_UNUSED = 0x1 | NETLINK_UNUSED = 0x1 | ||||
| NETLINK_USERSOCK = 0x2 | NETLINK_USERSOCK = 0x2 | ||||
| NETLINK_XFRM = 0x6 | NETLINK_XFRM = 0x6 | ||||
| NETNSA_MAX = 0x3 | |||||
| NETNSA_MAX = 0x5 | |||||
| NETNSA_NSID_NOT_ASSIGNED = -0x1 | NETNSA_NSID_NOT_ASSIGNED = -0x1 | ||||
| NFNETLINK_V0 = 0x0 | NFNETLINK_V0 = 0x0 | ||||
| NFNLGRP_ACCT_QUOTA = 0x8 | NFNLGRP_ACCT_QUOTA = 0x8 | ||||
| @@ -1398,6 +1444,12 @@ const ( | |||||
| PR_MCE_KILL_SET = 0x1 | PR_MCE_KILL_SET = 0x1 | ||||
| PR_MPX_DISABLE_MANAGEMENT = 0x2c | PR_MPX_DISABLE_MANAGEMENT = 0x2c | ||||
| PR_MPX_ENABLE_MANAGEMENT = 0x2b | PR_MPX_ENABLE_MANAGEMENT = 0x2b | ||||
| PR_PAC_APDAKEY = 0x4 | |||||
| PR_PAC_APDBKEY = 0x8 | |||||
| PR_PAC_APGAKEY = 0x10 | |||||
| PR_PAC_APIAKEY = 0x1 | |||||
| PR_PAC_APIBKEY = 0x2 | |||||
| PR_PAC_RESET_KEYS = 0x36 | |||||
| PR_SET_CHILD_SUBREAPER = 0x24 | PR_SET_CHILD_SUBREAPER = 0x24 | ||||
| PR_SET_DUMPABLE = 0x4 | PR_SET_DUMPABLE = 0x4 | ||||
| PR_SET_ENDIAN = 0x14 | PR_SET_ENDIAN = 0x14 | ||||
| @@ -2232,6 +2284,7 @@ const ( | |||||
| TUNGETVNETBE = 0x800454df | TUNGETVNETBE = 0x800454df | ||||
| TUNGETVNETHDRSZ = 0x800454d7 | TUNGETVNETHDRSZ = 0x800454d7 | ||||
| TUNGETVNETLE = 0x800454dd | TUNGETVNETLE = 0x800454dd | ||||
| TUNSETCARRIER = 0x400454e2 | |||||
| TUNSETDEBUG = 0x400454c9 | TUNSETDEBUG = 0x400454c9 | ||||
| TUNSETFILTEREBPF = 0x800454e1 | TUNSETFILTEREBPF = 0x800454e1 | ||||
| TUNSETGROUP = 0x400454ce | TUNSETGROUP = 0x400454ce | ||||