| @@ -74,6 +74,23 @@ WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP] | |||
| ; List of reasons why a Pull Request or Issue can be locked | |||
| 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] | |||
| ; Number of repositories that are displayed on one explore page | |||
| 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 | |||
| ## 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`) | |||
| - `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/RoaringBitmap/roaring v0.4.7 // indirect | |||
| 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/paginater v0.0.0-20151104151617-7748a72e0141 | |||
| 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/cache v0.0.0-20151013081102-561735312776 | |||
| 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/i18n v0.0.0-20160612092837-ef57533c3b0f | |||
| 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/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 | |||
| 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/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 | |||
| gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect | |||
| gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect | |||
| gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect | |||
| gopkg.in/editorconfig/editorconfig-core-go.v1 v1.2.0 | |||
| 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/macaron.v1 v1.3.2 | |||
| gopkg.in/redis.v2 v2.3.2 // indirect | |||
| @@ -135,6 +136,6 @@ require ( | |||
| ) | |||
| 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/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/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/go.mod h1:SFtfq0zFPsENI7DpE87QM2hcYu5QQ0fRdCgP+P1Hrqo= | |||
| 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/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/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/go.mod h1:oZGMxI7MBnicI0jJqJvH4qQzyrWKhtiKxLSJKHC+ydc= | |||
| 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/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-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/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | |||
| 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/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= | |||
| 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/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
| 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/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-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/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= | |||
| 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-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-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-20180826012351-8a410e7b638d/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-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-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/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
| 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/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/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/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= | |||
| 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) | |||
| newCacheService() | |||
| newSessionService() | |||
| newCORSService() | |||
| newMailService() | |||
| newRegisterMailService() | |||
| newNotifyMailService() | |||
| @@ -74,7 +74,8 @@ import ( | |||
| "code.gitea.io/gitea/routers/api/v1/user" | |||
| "github.com/go-macaron/binding" | |||
| "gopkg.in/macaron.v1" | |||
| "github.com/go-macaron/cors" | |||
| macaron "gopkg.in/macaron.v1" | |||
| ) | |||
| func sudo() macaron.Handler { | |||
| @@ -500,6 +501,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| 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() { | |||
| // Miscellaneous | |||
| if setting.API.EnableSwagger { | |||
| @@ -841,5 +848,15 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/topics", func() { | |||
| 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() | |||
| } | |||
| 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) | |||
| if err != nil { | |||
| return nil, err | |||
| @@ -56,13 +56,29 @@ func statDir(dirPath, recPath string, includeDir, isDirOnly bool) ([]string, err | |||
| if includeDir { | |||
| statList = append(statList, relPath+"/") | |||
| } | |||
| s, err := statDir(curPath, relPath, includeDir, isDirOnly) | |||
| s, err := statDir(curPath, relPath, includeDir, isDirOnly, followSymlinks) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| statList = append(statList, s...) | |||
| } else if !isDirOnly { | |||
| 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 | |||
| @@ -84,7 +100,26 @@ func StatDir(rootPath string, includeDir ...bool) ([]string, error) { | |||
| if len(includeDir) >= 1 { | |||
| 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. | |||
| @@ -93,7 +128,17 @@ func GetAllSubDirs(rootPath string) ([]string, error) { | |||
| if !IsDir(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. | |||
| @@ -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) | |||
| } | |||
| // decode string to html chars | |||
| // HtmlDecode decodes string to html chars | |||
| func HtmlDecode(str string) string { | |||
| return html.UnescapeString(str) | |||
| } | |||
| @@ -177,7 +177,7 @@ func FetchFiles(client *http.Client, files []RawFile, header http.Header) error | |||
| 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 { | |||
| ch := make(chan error, len(files)) | |||
| for i := range files { | |||
| @@ -14,12 +14,12 @@ | |||
| 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 { | |||
| if y <= 0 { | |||
| return 1 | |||
| } else { | |||
| if y % 2 == 0 { | |||
| if y%2 == 0 { | |||
| sqrt := PowInt(x, y/2) | |||
| return sqrt * sqrt | |||
| } else { | |||
| @@ -37,19 +37,19 @@ func init() { | |||
| 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 | |||
| func IsEmail(email string) bool { | |||
| 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 | |||
| func IsEmailRFC(email string) bool { | |||
| 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 | |||
| func IsUrl(url string) bool { | |||
| return regex_url.MatchString(url) | |||
| @@ -44,7 +44,7 @@ func CompareSliceStr(s1, s2 []string) bool { | |||
| 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. | |||
| func CompareSliceStrU(s1, s2 []string) bool { | |||
| 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 { | |||
| // Key is the account key used to register with a CA and sign requests. | |||
| // 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 | |||
| // 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 | |||
| } | |||
| 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 { | |||
| return Directory{}, err | |||
| } | |||
| @@ -161,6 +161,13 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { | |||
| 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. | |||
| // The exp argument indicates the desired certificate validity duration. CA may issue a certificate | |||
| // 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 | |||
| // need not fulfill any challenge and can proceed to requesting a certificate. | |||
| 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 { | |||
| return nil, err | |||
| } | |||
| @@ -332,7 +353,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, | |||
| Identifier authzID `json:"identifier"` | |||
| }{ | |||
| 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)) | |||
| 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 | |||
| // 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) { | |||
| c.noncesMu.Lock() | |||
| defer c.noncesMu.Unlock() | |||
| 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 | |||
| for nonce = range c.nonces { | |||
| @@ -69,7 +69,7 @@ func HostWhitelist(hosts ...string) HostPolicy { | |||
| } | |||
| return func(_ context.Context, host string) error { | |||
| 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 | |||
| } | |||
| @@ -25,7 +25,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byt | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| alg, sha := jwsHasher(key) | |||
| alg, sha := jwsHasher(key.Public()) | |||
| if alg == "" || !sha.Available() { | |||
| return nil, ErrUnsupportedKey | |||
| } | |||
| @@ -97,13 +97,16 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { | |||
| } | |||
| // 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) { | |||
| 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) | |||
| if err != nil { | |||
| 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) | |||
| return sig, nil | |||
| } | |||
| return nil, ErrUnsupportedKey | |||
| return key.Sign(rand.Reader, digest, hash) | |||
| } | |||
| // jwsHasher indicates suitable JWS algorithm name and a hash function | |||
| // to use for signing a digest with the provided key. | |||
| // 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 | |||
| case *ecdsa.PrivateKey: | |||
| switch key.Params().Name { | |||
| case *ecdsa.PublicKey: | |||
| switch pub.Params().Name { | |||
| case "P-256": | |||
| return "ES256", crypto.SHA256 | |||
| case "P-384": | |||
| @@ -3,6 +3,14 @@ | |||
| // license that can be found in the LICENSE file. | |||
| // 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" | |||
| // 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 | |||
| // 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" | |||
| import "errors" | |||
| @@ -86,7 +86,7 @@ func feFromBytes(dst *fieldElement, src *[32]byte) { | |||
| h6 := load3(src[20:]) << 7 | |||
| h7 := load3(src[23:]) << 5 | |||
| h8 := load3(src[26:]) << 4 | |||
| h9 := load3(src[29:]) << 2 | |||
| h9 := (load3(src[29:]) & 0x7fffff) << 2 | |||
| var carry [10]int64 | |||
| carry[9] = (h9 + 1<<24) >> 25 | |||
| @@ -121,18 +121,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -236,18 +236,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -441,18 +441,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -591,18 +591,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -731,18 +731,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -846,18 +846,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -996,18 +996,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -1146,18 +1146,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -1332,18 +1332,18 @@ TEXT ·ladderstep(SB),0,$296-8 | |||
| ADDQ AX,R12 | |||
| ADCQ DX,R13 | |||
| MOVQ $REDMASK51,DX | |||
| SHLQ $13,CX:SI | |||
| SHLQ $13,SI,CX | |||
| ANDQ DX,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ DX,R8 | |||
| ADDQ CX,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ DX,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ DX,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ DX,R14 | |||
| ADDQ R13,R14 | |||
| IMUL3Q $19,R15,CX | |||
| @@ -124,18 +124,18 @@ TEXT ·mul(SB),0,$16-24 | |||
| ADDQ AX,R14 | |||
| ADCQ DX,R15 | |||
| MOVQ $REDMASK51,SI | |||
| SHLQ $13,R9:R8 | |||
| SHLQ $13,R8,R9 | |||
| ANDQ SI,R8 | |||
| SHLQ $13,R11:R10 | |||
| SHLQ $13,R10,R11 | |||
| ANDQ SI,R10 | |||
| ADDQ R9,R10 | |||
| SHLQ $13,R13:R12 | |||
| SHLQ $13,R12,R13 | |||
| ANDQ SI,R12 | |||
| ADDQ R11,R12 | |||
| SHLQ $13,R15:R14 | |||
| SHLQ $13,R14,R15 | |||
| ANDQ SI,R14 | |||
| ADDQ R13,R14 | |||
| SHLQ $13,BP:BX | |||
| SHLQ $13,BX,BP | |||
| ANDQ SI,BX | |||
| ADDQ R15,BX | |||
| IMUL3Q $19,BP,DX | |||
| @@ -87,18 +87,18 @@ TEXT ·square(SB),7,$0-16 | |||
| ADDQ AX,R13 | |||
| ADCQ DX,R14 | |||
| MOVQ $REDMASK51,SI | |||
| SHLQ $13,R8:CX | |||
| SHLQ $13,CX,R8 | |||
| ANDQ SI,CX | |||
| SHLQ $13,R10:R9 | |||
| SHLQ $13,R9,R10 | |||
| ANDQ SI,R9 | |||
| ADDQ R8,R9 | |||
| SHLQ $13,R12:R11 | |||
| SHLQ $13,R11,R12 | |||
| ANDQ SI,R11 | |||
| ADDQ R10,R11 | |||
| SHLQ $13,R14:R13 | |||
| SHLQ $13,R13,R14 | |||
| ANDQ SI,R13 | |||
| ADDQ R12,R13 | |||
| SHLQ $13,BX:R15 | |||
| SHLQ $13,R15,BX | |||
| ANDQ SI,R15 | |||
| ADDQ R14,R15 | |||
| 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 | |||
| // license that can be found in the LICENSE file. | |||
| // +build !s390x gccgo appengine | |||
| // +build !arm64,!s390x arm64,!go1.11 gccgo appengine | |||
| package chacha20 | |||
| @@ -6,14 +6,13 @@ | |||
| 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 | |||
| // be called when the vector facility is available. | |||
| @@ -258,26 +258,3 @@ tail: | |||
| MOVD R8, R3 | |||
| MOVD $0, R4 | |||
| 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. | |||
| // 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" | |||
| import ( | |||
| @@ -333,7 +333,6 @@ func ReadEntity(packets *packet.Reader) (*Entity, error) { | |||
| return nil, errors.StructuralError("primary key cannot be used for signatures") | |||
| } | |||
| var current *Identity | |||
| var revocations []*packet.Signature | |||
| EachPacket: | |||
| for { | |||
| @@ -346,36 +345,8 @@ EachPacket: | |||
| switch pkt := p.(type) { | |||
| 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: | |||
| if pkt.SigType == packet.SigTypeKeyRevocation { | |||
| @@ -384,11 +355,9 @@ EachPacket: | |||
| // TODO: RFC4880 5.2.1 permits signatures | |||
| // directly on keys (eg. to bind additional | |||
| // 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: | |||
| if pkt.IsSubkey == false { | |||
| packets.Unread(p) | |||
| @@ -429,33 +398,105 @@ EachPacket: | |||
| 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 { | |||
| var subKey Subkey | |||
| subKey.PublicKey = pub | |||
| 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") | |||
| } | |||
| 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) | |||
| 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 | |||
| // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a | |||
| @@ -404,14 +404,16 @@ const ( | |||
| type PublicKeyAlgorithm uint8 | |||
| 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. | |||
| PubKeyAlgoECDH PublicKeyAlgorithm = 18 | |||
| 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 | |||
| @@ -64,14 +64,19 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK | |||
| 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. | |||
| func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *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) { | |||
| case *rsa.PublicKey: | |||
| pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) | |||
| case rsa.PublicKey: | |||
| pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) | |||
| pk.PubKeyAlgo = PubKeyAlgoRSASignOnly | |||
| case *ecdsa.PublicKey: | |||
| pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) | |||
| case ecdsa.PublicKey: | |||
| pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) | |||
| 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) | |||
| } else { | |||
| 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 { | |||
| 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 | |||
| // JPEG File Interchange Format (JFIF), for each photo in the | |||
| // the user attribute packet. | |||
| // user attribute packet. | |||
| func (uat *UserAttribute) ImageData() (imageData [][]byte) { | |||
| for _, sp := range uat.Contents { | |||
| 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. | |||
| candidateHashes := []uint8{ | |||
| hashToHashId(crypto.SHA256), | |||
| hashToHashId(crypto.SHA384), | |||
| hashToHashId(crypto.SHA512), | |||
| hashToHashId(crypto.SHA1), | |||
| 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. | |||
| candidateHashes := []uint8{ | |||
| hashToHashId(crypto.SHA256), | |||
| hashToHashId(crypto.SHA384), | |||
| hashToHashId(crypto.SHA512), | |||
| hashToHashId(crypto.SHA1), | |||
| 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 | |||
| // 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" | |||
| import "crypto/subtle" | |||
| @@ -31,3 +29,55 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool { | |||
| Sum(&tmp, m, key) | |||
| 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 | |||
| // This function is implemented in sum_amd64.s | |||
| //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 | |||
| // 16-byte result into out. Authenticating two different messages with the same | |||
| // key allows an attacker to forge messages at will. | |||
| 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 | |||
| 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 | |||
| JB bytes_between_0_and_15 | |||
| @@ -109,16 +106,42 @@ flush_buffer: | |||
| JMP multiply | |||
| 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 | |||
| SBBQ $0xFFFFFFFFFFFFFFFF, BX | |||
| SBBQ $3, R10 | |||
| SBBQ $3, CX | |||
| CMOVQCS R8, AX | |||
| 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 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 | |||
| // license that can be found in the LICENSE file. | |||
| @@ -6,21 +6,79 @@ package poly1305 | |||
| import "encoding/binary" | |||
| const ( | |||
| msgBlock = uint32(1 << 24) | |||
| finalBlock = uint32(0) | |||
| ) | |||
| // 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 | |||
| // Sum and should be called if no assembly implementation is available. | |||
| 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 | |||
| 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 | |||
| h2 += (binary.LittleEndian.Uint32(msg[6:]) >> 4) & 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 | |||
| 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:] | |||
| } | |||
| 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 | |||
| h2 += h1 >> 26 | |||
| @@ -123,13 +156,13 @@ func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { | |||
| // s: the s part of the key | |||
| // tag = (h + s) % (2^128) | |||
| t := uint64(h0) + uint64(binary.LittleEndian.Uint32(key[16:])) | |||
| t := uint64(h0) + uint64(s[0]) | |||
| 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) | |||
| t = uint64(h2) + uint64(binary.LittleEndian.Uint32(key[24:])) + (t >> 32) | |||
| t = uint64(h2) + uint64(s[2]) + (t >> 32) | |||
| 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) | |||
| binary.LittleEndian.PutUint32(out[0:], h0) | |||
| @@ -10,5 +10,7 @@ package poly1305 | |||
| // 16-byte result into out. Authenticating two different messages with the same | |||
| // key allows an attacker to forge messages at will. | |||
| 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 | |||
| // 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 | |||
| // 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 | |||
| // key allows an attacker to forge messages at will. | |||
| func Sum(out *[16]byte, m []byte, key *[32]byte) { | |||
| if hasVX { | |||
| if cpu.S390X.HasVX { | |||
| var mPtr *byte | |||
| if len(m) > 0 { | |||
| mPtr = &m[0] | |||
| } | |||
| if hasVMSL && len(m) > 256 { | |||
| if cpu.S390X.HasVXE && len(m) > 256 { | |||
| poly1305vmsl(out, mPtr, uint64(len(m)), key) | |||
| } else { | |||
| poly1305vx(out, mPtr, uint64(len(m)), key) | |||
| @@ -376,25 +376,3 @@ b1: | |||
| MOVD $0, R3 | |||
| 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) | |||
| REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) | |||
| 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" | |||
| "sync" | |||
| "crypto" | |||
| "golang.org/x/crypto/ed25519" | |||
| "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. | |||
| type Agent interface { | |||
| // List returns the identities known to the agent. | |||
| @@ -57,6 +69,26 @@ type Agent interface { | |||
| 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. | |||
| type ConstraintExtension struct { | |||
| // ExtensionName consist of a UTF-8 string suffixed by the | |||
| @@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct { | |||
| 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 | |||
| // [PROTOCOL.agent], section 2.5.2. | |||
| type Key struct { | |||
| @@ -260,7 +309,7 @@ type client struct { | |||
| // NewClient returns an Agent that talks to an ssh-agent process over | |||
| // the given connection. | |||
| func NewClient(rw io.ReadWriter) Agent { | |||
| func NewClient(rw io.ReadWriter) ExtendedAgent { | |||
| 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 | |||
| // the reply, which contains the type of the message. | |||
| 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() | |||
| defer c.mu.Unlock() | |||
| @@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) { | |||
| } | |||
| respSize := binary.BigEndian.Uint32(respSizeBuf[:]) | |||
| if respSize > maxAgentResponseBytes { | |||
| return nil, clientErr(err) | |||
| return nil, clientErr(errors.New("response too large")) | |||
| } | |||
| buf := make([]byte, respSize) | |||
| if _, err = io.ReadFull(c.conn, buf); err != nil { | |||
| 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 { | |||
| @@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) { | |||
| // Sign has the agent sign the data using a protocol 2 key as defined | |||
| // in [PROTOCOL.agent] section 2.6.2. | |||
| 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{ | |||
| KeyBlob: key.Marshal(), | |||
| Data: data, | |||
| Flags: uint32(flags), | |||
| }) | |||
| 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. | |||
| 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. | |||
| 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() | |||
| defer r.mu.Unlock() | |||
| if r.locked { | |||
| @@ -192,7 +196,24 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | |||
| wanted := key.Marshal() | |||
| for _, k := range r.keys { | |||
| 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") | |||
| @@ -213,3 +234,8 @@ func (r *keyring) Signers() ([]ssh.Signer, error) { | |||
| } | |||
| 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, | |||
| } | |||
| 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 { | |||
| return nil, err | |||
| } | |||
| @@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) { | |||
| case agentAddIDConstrained, agentAddIdentity: | |||
| 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]) | |||
| @@ -497,6 +541,9 @@ func ServeAgent(agent Agent, c io.ReadWriter) error { | |||
| return err | |||
| } | |||
| l := binary.BigEndian.Uint32(length[:]) | |||
| if l == 0 { | |||
| return fmt.Errorf("agent: request size is 0") | |||
| } | |||
| if l > maxAgentResponseBytes { | |||
| // We also cap requests. | |||
| return fmt.Errorf("agent: request too large: %d", l) | |||
| @@ -222,6 +222,11 @@ type openSSHCertSigner struct { | |||
| signer Signer | |||
| } | |||
| type algorithmOpenSSHCertSigner struct { | |||
| *openSSHCertSigner | |||
| algorithmSigner AlgorithmSigner | |||
| } | |||
| // 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 | |||
| // 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 &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) { | |||
| @@ -241,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey { | |||
| 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" | |||
| // CertChecker does the work of verifying a certificate. Its methods | |||
| @@ -149,8 +149,8 @@ type streamPacketCipher struct { | |||
| 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 { | |||
| 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 | |||
| } | |||
| // 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 { | |||
| return errors.New("ssh: packet too large") | |||
| } | |||
| @@ -327,7 +327,7 @@ func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) | |||
| 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 | |||
| // stream cipher because that encrypts the length too. | |||
| 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 { | |||
| return nil, err | |||
| } | |||
| @@ -486,8 +486,8 @@ type cbcError string | |||
| 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 _, ok := err.(cbcError); ok { | |||
| // 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 | |||
| } | |||
| 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() | |||
| // 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 | |||
| } | |||
| 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()) | |||
| // 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 | |||
| } | |||
| 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)} | |||
| s := chacha20.New(c.contentKey, nonce) | |||
| var polyKey [32]byte | |||
| @@ -723,7 +723,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, | |||
| 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)} | |||
| s := chacha20.New(c.contentKey, nonce) | |||
| 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 | |||
| // an error to reject it. It receives the hostname as passed to Dial | |||
| // 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 | |||
| // 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) | |||
| } | |||
| // directionAlgorithms records algorithm choices in one direction (either read or write) | |||
| type directionAlgorithms struct { | |||
| Cipher string | |||
| MAC string | |||
| @@ -137,7 +138,7 @@ type algorithms struct { | |||
| 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.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) | |||
| @@ -150,32 +151,37 @@ func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor | |||
| 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 { | |||
| 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 { | |||
| 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 { | |||
| 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 { | |||
| 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 { | |||
| 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 { | |||
| return | |||
| } | |||
| @@ -543,7 +543,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | |||
| clientInit := otherInit | |||
| serverInit := t.sentInitMsg | |||
| if len(t.hostKeys) == 0 { | |||
| isClient := len(t.hostKeys) == 0 | |||
| if isClient { | |||
| clientInit, serverInit = serverInit, clientInit | |||
| magics.clientKexInit = t.sentInitPacket | |||
| @@ -551,7 +552,7 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | |||
| } | |||
| var err error | |||
| t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) | |||
| t.algorithms, err = findAgreedAlgorithms(isClient, clientInit, serverInit) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| @@ -38,6 +38,16 @@ const ( | |||
| 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. | |||
| // Use ParsePublicKey for keys with prepended algorithm. | |||
| 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) | |||
| } | |||
| // 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 | |||
| func (r *rsaPublicKey) Type() string { | |||
| @@ -349,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte { | |||
| } | |||
| 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()) | |||
| } | |||
| h := crypto.SHA1.New() | |||
| h := hash.New() | |||
| h.Write(data) | |||
| 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 { | |||
| @@ -459,6 +490,14 @@ func (k *dsaPrivateKey) PublicKey() PublicKey { | |||
| } | |||
| 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.Write(data) | |||
| digest := h.Sum(nil) | |||
| @@ -691,16 +730,42 @@ func (s *wrappedSigner) PublicKey() PublicKey { | |||
| } | |||
| 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 | |||
| 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 | |||
| @@ -745,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | |||
| } | |||
| return &Signature{ | |||
| Format: s.pubKey.Type(), | |||
| Format: algorithm, | |||
| Blob: signature, | |||
| }, nil | |||
| } | |||
| @@ -350,8 +350,8 @@ func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.Public | |||
| 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. | |||
| func (db *hostKeyDB) checkAddr(a addr, remoteKey ssh.PublicKey) error { | |||
| // TODO(hanwen): are these the right semantics? What if there | |||
| @@ -764,3 +764,29 @@ func decode(packet []byte) (interface{}, error) { | |||
| } | |||
| 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) | |||
| case "keyboard-interactive": | |||
| if config.KeyboardInteractiveCallback == nil { | |||
| authErr = errors.New("ssh: keyboard-interactive auth not configubred") | |||
| authErr = errors.New("ssh: keyboard-interactive auth not configured") | |||
| break | |||
| } | |||
| @@ -484,6 +484,7 @@ userAuthLoop: | |||
| // sig.Format. This is usually the same, but | |||
| // for certs, the names differ. | |||
| if !isAcceptableAlgo(sig.Format) { | |||
| authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) | |||
| break | |||
| } | |||
| signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) | |||
| @@ -53,14 +53,14 @@ type transport struct { | |||
| // packetCipher represents a combination of SSH encryption/MAC | |||
| // protocol. A single instance should be used for one direction only. | |||
| 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. | |||
| 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 | |||
| // 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 | |||
| @@ -127,7 +127,7 @@ func (t *transport) readPacket() (p []byte, err 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++ | |||
| if err == nil && len(packet) == 0 { | |||
| 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 { | |||
| 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 { | |||
| 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 | |||
| if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; 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 | |||
| fi | |||
| ) | $run | |||
| @@ -192,6 +192,7 @@ struct ltchars { | |||
| #include <linux/if_packet.h> | |||
| #include <linux/if_addr.h> | |||
| #include <linux/falloc.h> | |||
| #include <linux/fanotify.h> | |||
| #include <linux/filter.h> | |||
| #include <linux/fs.h> | |||
| #include <linux/kexec.h> | |||
| @@ -501,6 +502,7 @@ ccflags="$@" | |||
| $2 !~ "WMESGLEN" && | |||
| $2 ~ /^W[A-Z0-9]+$/ || | |||
| $2 ~/^PPPIOC/ || | |||
| $2 ~ /^FAN_|FANOTIFY_/ || | |||
| $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} | |||
| $2 ~ /^__WCOREFLAG$/ {next} | |||
| $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] | |||
| // 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. | |||
| in := parseParamList(inps) | |||
| out := parseParamList(outps) | |||
| @@ -228,7 +233,7 @@ func main() { | |||
| } else { | |||
| 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 { | |||
| // arm abi specifies 64-bit argument uses | |||
| // (even, odd) pair | |||
| @@ -25,8 +25,8 @@ func cmsgAlignOf(salen int) int { | |||
| if SizeofPtr == 8 { | |||
| 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" { | |||
| salign = 8 | |||
| } | |||
| @@ -545,3 +545,5 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
| //sys gettimeofday(tv *Timeval, tzp *Timezone) (err error) | |||
| //sysnb Time(t *Time_t) (tt Time_t, 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) | |||
| 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) | |||
| 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) | |||
| } | |||
| //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) | |||
| 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 | |||
| } | |||
| 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) { | |||
| 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 | |||
| // socket to filter incoming packets. See 'man 7 socket' for usage information. | |||
| 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)) | |||
| } | |||
| 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) | |||
| // 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)} | |||
| } | |||
| //sysnb pipe(p *[2]_C_int) (err error) | |||
| func Pipe(p []int) (err error) { | |||
| if len(p) != 2 { | |||
| return EINVAL | |||
| } | |||
| var pp [2]_C_int | |||
| // Try pipe2 first for Android O, then try pipe for kernel 2.6.23. | |||
| err = pipe2(&pp, 0) | |||
| if err == ENOSYS { | |||
| err = pipe(&pp) | |||
| } | |||
| p[0] = int(pp[0]) | |||
| p[1] = int(pp[1]) | |||
| return | |||
| @@ -208,3 +208,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { | |||
| } | |||
| 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) { | |||
| 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 | |||
| } | |||
| 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) { | |||
| mib, err := sysctlmib(name) | |||
| if err != nil { | |||
| @@ -28,6 +28,11 @@ var ( | |||
| errENOENT error = syscall.ENOENT | |||
| ) | |||
| var ( | |||
| signalNameMapOnce sync.Once | |||
| signalNameMap map[string]syscall.Signal | |||
| ) | |||
| // errnoErr returns common boxed Errno values, to prevent | |||
| // allocations at runtime. | |||
| func errnoErr(e syscall.Errno) error { | |||
| @@ -66,6 +71,19 @@ func SignalName(s syscall.Signal) string { | |||
| 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. | |||
| func clen(n []byte) int { | |||
| i := bytes.IndexByte(n, 0) | |||
| @@ -276,6 +294,13 @@ func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) { | |||
| 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) { | |||
| var rsa RawSockaddrAny | |||
| 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)) | |||
| } | |||
| 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) { | |||
| if domain == AF_INET6 && SocketDisableIPv6 { | |||
| return -1, EAFNOSUPPORT | |||
| @@ -377,3 +406,22 @@ func SetNonblock(fd int, nonblocking bool) (err error) { | |||
| func Exec(argv0 string, argv []string, envv []string) error { | |||
| 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 | |||
| 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 | |||
| type Uvmexp C.struct_uvmexp | |||
| // Clockinfo | |||
| const SizeofClockinfo = C.sizeof_struct_clockinfo | |||
| type Clockinfo C.struct_clockinfo | |||
| @@ -174,6 +174,7 @@ const ( | |||
| B9600 = 0xd | |||
| BALLOON_KVM_MAGIC = 0x13661366 | |||
| BDEVFS_MAGIC = 0x62646576 | |||
| BINDERFS_SUPER_MAGIC = 0x6c6f6f70 | |||
| BINFMTFS_MAGIC = 0x42494e4d | |||
| BLKBSZGET = 0x80041270 | |||
| BLKBSZSET = 0x40041271 | |||
| @@ -486,6 +487,50 @@ const ( | |||
| FALLOC_FL_PUNCH_HOLE = 0x2 | |||
| FALLOC_FL_UNSHARE_RANGE = 0x40 | |||
| 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_SETSIZE = 0x400 | |||
| FF0 = 0x0 | |||
| @@ -493,6 +538,7 @@ const ( | |||
| FFDLY = 0x8000 | |||
| FLUSHO = 0x1000 | |||
| FP_XSTATE_MAGIC2 = 0x46505845 | |||
| FS_ENCRYPTION_MODE_ADIANTUM = 0x9 | |||
| FS_ENCRYPTION_MODE_AES_128_CBC = 0x5 | |||
| FS_ENCRYPTION_MODE_AES_128_CTS = 0x6 | |||
| FS_ENCRYPTION_MODE_AES_256_CBC = 0x3 | |||
| @@ -514,7 +560,7 @@ const ( | |||
| FS_POLICY_FLAGS_PAD_4 = 0x0 | |||
| FS_POLICY_FLAGS_PAD_8 = 0x1 | |||
| FS_POLICY_FLAGS_PAD_MASK = 0x3 | |||
| FS_POLICY_FLAGS_VALID = 0x3 | |||
| FS_POLICY_FLAGS_VALID = 0x7 | |||
| FUTEXFS_SUPER_MAGIC = 0xbad1dea | |||
| F_ADD_SEALS = 0x409 | |||
| F_DUPFD = 0x0 | |||
| @@ -1134,7 +1180,7 @@ const ( | |||
| NETLINK_UNUSED = 0x1 | |||
| NETLINK_USERSOCK = 0x2 | |||
| NETLINK_XFRM = 0x6 | |||
| NETNSA_MAX = 0x3 | |||
| NETNSA_MAX = 0x5 | |||
| NETNSA_NSID_NOT_ASSIGNED = -0x1 | |||
| NFNETLINK_V0 = 0x0 | |||
| NFNLGRP_ACCT_QUOTA = 0x8 | |||
| @@ -1398,6 +1444,12 @@ const ( | |||
| PR_MCE_KILL_SET = 0x1 | |||
| PR_MPX_DISABLE_MANAGEMENT = 0x2c | |||
| 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_DUMPABLE = 0x4 | |||
| PR_SET_ENDIAN = 0x14 | |||
| @@ -2232,6 +2284,7 @@ const ( | |||
| TUNGETVNETBE = 0x800454df | |||
| TUNGETVNETHDRSZ = 0x800454d7 | |||
| TUNGETVNETLE = 0x800454dd | |||
| TUNSETCARRIER = 0x400454e2 | |||
| TUNSETDEBUG = 0x400454c9 | |||
| TUNSETFILTEREBPF = 0x800454e1 | |||
| TUNSETGROUP = 0x400454ce | |||