Deps update, gopkg.lock fix, flagger initialization fix.
This commit is contained in:
parent
23510e22a0
commit
afb076d116
Gopkg.lockGopkg.toml
config
context
parsers/default
vendor
github.com/sirupsen/logrus
.gitignore.travis.ymlCHANGELOG.mdREADME.mdalt_exit_test.goentry.goentry_test.goexample_basic_test.goexample_hook_test.goexported.goformatter.gohook_test.go
hooks
json_formatter.gojson_formatter_test.gologger.gologger_bench_test.gologrus.gologrus_test.goterminal_bsd.goterminal_check_notappengine.goterminal_linux.gotext_formatter.gotext_formatter_test.gowriter.gogolang.org/x/crypto
CONTRIBUTING.md
acme
argon2
bcrypt
blake2b
blake2b.goblake2bAVX2_amd64.goblake2bAVX2_amd64.sblake2b_amd64.goblake2b_amd64.sblake2b_test.goblake2x.go
blake2s
blowfish
bn256
cast5
chacha20poly1305
chacha20poly1305.gochacha20poly1305_amd64.gochacha20poly1305_amd64.schacha20poly1305_generic.gochacha20poly1305_test.gochacha20poly1305_vectors_test.go
cryptobyte
curve25519
ed25519
hkdf
internal/chacha20
md4
nacl/secretbox
ocsp
openpgp
62
Gopkg.lock
generated
62
Gopkg.lock
generated
@ -2,47 +2,71 @@
|
||||
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6a874e3ddfb9db2b42bd8c85b6875407c702fa868eed20634ff489bc896ccfd3"
|
||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:58942e5575baa224511b2cdda65b643bae65cea4e205a779198072205b9d91f7"
|
||||
name = "github.com/pztrn/mogrus"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "2d9bba232129a20da87a9a9ab404b0f33c218622"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9a3c631555e0351fdc4e696577bb63afd90c399d782a8462dba9d100d7021db3"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "d682213848ed68c0a260ca37d6dd5ace8423f5ba"
|
||||
version = "v1.0.4"
|
||||
pruneopts = ""
|
||||
revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e08724b3e77d1ce400cff5185a4532f01cacc8059dd5a619fdf4a91e79374dfa"
|
||||
name = "gitlab.com/pztrn/flagger"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "d429d7149cc92b7eaa7c98ab3d80b6d5c2e44046"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d0f4eb7abce3fbd3f0dcbbc03ffe18464846afd34c815928d2ae11c1e5aded04"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
revision = "1875d0a70c90e57f11972aefd42276df65e895b9"
|
||||
pruneopts = ""
|
||||
revision = "ffb98f73852f696ea2bb21a617a5c4b3e067a439"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:d8c7c5e28d31494f02b25867de6827adaa90005f0ff3407f3336751fc0bc7432"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows"
|
||||
"windows",
|
||||
]
|
||||
revision = "8f27ce8a604014414f8dfffc25cbcde83a3f2216"
|
||||
pruneopts = ""
|
||||
revision = "cc5685c2db1239775905f3911f0067c0fa74762f"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:cedccf16b71e86db87a24f8d4c70b0a855872eb967cb906a66b95de56aefbd0d"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "source.pztrn.name/golibs/flagger"
|
||||
packages = ["."]
|
||||
revision = "c9b4726e1787adb01126cdf9a7932e2bccbb51a7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "source.pztrn.name/golibs/mogrus"
|
||||
packages = ["."]
|
||||
revision = "2e3a9d38c8e4b0036f714f88ef0fe9fc14b4c6b8"
|
||||
pruneopts = ""
|
||||
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "2b99cf1ed594e6ce9e2bc8bf1be8cbe0018db897ef6dc6c3e59ae5030099ef48"
|
||||
input-imports = [
|
||||
"github.com/pztrn/mogrus",
|
||||
"gitlab.com/pztrn/flagger",
|
||||
"gopkg.in/yaml.v2",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "source.pztrn.name/golibs/flagger"
|
||||
name = "gitlab.com/pztrn/flagger"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "source.pztrn.name/golibs/mogrus"
|
||||
name = "github.com/pztrn/mogrus"
|
||||
|
@ -29,8 +29,8 @@ import (
|
||||
"gitlab.com/pztrn/opensaps/config/struct"
|
||||
|
||||
// other
|
||||
"gitlab.com/pztrn/flagger"
|
||||
"gopkg.in/yaml.v2"
|
||||
"source.pztrn.name/golibs/flagger"
|
||||
)
|
||||
|
||||
type Configuration struct{}
|
||||
|
@ -30,8 +30,8 @@ import (
|
||||
"gitlab.com/pztrn/opensaps/slack/message"
|
||||
|
||||
// other
|
||||
"source.pztrn.name/golibs/flagger"
|
||||
"source.pztrn.name/golibs/mogrus"
|
||||
"github.com/pztrn/mogrus"
|
||||
"gitlab.com/pztrn/flagger"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
@ -52,7 +52,7 @@ func (c *Context) Initialize() {
|
||||
c.Log = l.CreateLogger("opensaps")
|
||||
c.Log.CreateOutput("stdout", os.Stdout, true, "debug")
|
||||
|
||||
c.Flagger = flagger.New(c.Log)
|
||||
c.Flagger = flagger.New("opensaps", flagger.LoggerInterface(c.Log))
|
||||
c.Flagger.Initialize()
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,8 @@ package defaultparser
|
||||
|
||||
import (
|
||||
// local
|
||||
"gitlab.com/pztrn/misc/opensaps/context"
|
||||
"gitlab.com/pztrn/misc/opensaps/parsers/interface"
|
||||
"gitlab.com/pztrn/opensaps/context"
|
||||
"gitlab.com/pztrn/opensaps/parsers/interface"
|
||||
)
|
||||
|
||||
var (
|
||||
|
1
vendor/github.com/sirupsen/logrus/.gitignore
generated
vendored
1
vendor/github.com/sirupsen/logrus/.gitignore
generated
vendored
@ -1 +1,2 @@
|
||||
logrus
|
||||
vendor
|
||||
|
61
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
61
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
@ -1,15 +1,52 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- tip
|
||||
go_import_path: github.com/sirupsen/logrus
|
||||
env:
|
||||
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
||||
install:
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get gopkg.in/gemnasium/logrus-airbrake-hook.v2
|
||||
- go get golang.org/x/sys/unix
|
||||
- go get golang.org/x/sys/windows
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.10.x
|
||||
install:
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get golang.org/x/crypto/ssh/terminal
|
||||
- go get golang.org/x/sys/unix
|
||||
- go get golang.org/x/sys/windows
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
install:
|
||||
- go mod download
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=off
|
||||
install:
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get golang.org/x/crypto/ssh/terminal
|
||||
- go get golang.org/x/sys/unix
|
||||
- go get golang.org/x/sys/windows
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
- go: 1.10.x
|
||||
install:
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get golang.org/x/crypto/ssh/terminal
|
||||
- go get golang.org/x/sys/unix
|
||||
- go get golang.org/x/sys/windows
|
||||
script:
|
||||
- go test -race -v -tags appengine ./...
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
install:
|
||||
- go mod download
|
||||
script:
|
||||
- go test -race -v -tags appengine ./...
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=off
|
||||
install:
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get golang.org/x/crypto/ssh/terminal
|
||||
- go get golang.org/x/sys/unix
|
||||
- go get golang.org/x/sys/windows
|
||||
script:
|
||||
- go test -race -v -tags appengine ./...
|
||||
|
47
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
47
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
@ -1,3 +1,50 @@
|
||||
# 1.2.0
|
||||
This new release introduces:
|
||||
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
||||
* A new trace level named `Trace` whose level is below `Debug`
|
||||
* A configurable exit function to be called upon a Fatal trace
|
||||
* The `Level` object now implements `encoding.TextUnmarshaler` interface
|
||||
|
||||
# 1.1.1
|
||||
This is a bug fix release.
|
||||
* fix the build break on Solaris
|
||||
* don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
|
||||
|
||||
# 1.1.0
|
||||
This new release introduces:
|
||||
* several fixes:
|
||||
* a fix for a race condition on entry formatting
|
||||
* proper cleanup of previously used entries before putting them back in the pool
|
||||
* the extra new line at the end of message in text formatter has been removed
|
||||
* a new global public API to check if a level is activated: IsLevelEnabled
|
||||
* the following methods have been added to the Logger object
|
||||
* IsLevelEnabled
|
||||
* SetFormatter
|
||||
* SetOutput
|
||||
* ReplaceHooks
|
||||
* introduction of go module
|
||||
* an indent configuration for the json formatter
|
||||
* output colour support for windows
|
||||
* the field sort function is now configurable for text formatter
|
||||
* the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater
|
||||
|
||||
# 1.0.6
|
||||
|
||||
This new release introduces:
|
||||
* a new api WithTime which allows to easily force the time of the log entry
|
||||
which is mostly useful for logger wrapper
|
||||
* a fix reverting the immutability of the entry given as parameter to the hooks
|
||||
a new configuration field of the json formatter in order to put all the fields
|
||||
in a nested dictionnary
|
||||
* a new SetOutput method in the Logger
|
||||
* a new configuration of the textformatter to configure the name of the default keys
|
||||
* a new configuration of the text formatter to disable the level truncation
|
||||
|
||||
# 1.0.5
|
||||
|
||||
* Fix hooks race (#707)
|
||||
* Fix panic deadlock (#695)
|
||||
|
||||
# 1.0.4
|
||||
|
||||
* Fix race when adding hooks (#612)
|
||||
|
97
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
97
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
@ -56,8 +56,39 @@ time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased
|
||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||
exit status 1
|
||||
```
|
||||
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
|
||||
|
||||
```go
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
DisableColors: true,
|
||||
FullTimestamp: true,
|
||||
})
|
||||
```
|
||||
|
||||
#### Logging Method Name
|
||||
|
||||
If you wish to add the calling method as a field, instruct the logger via:
|
||||
```go
|
||||
log.SetReportCaller(true)
|
||||
```
|
||||
This adds the caller as 'method' like so:
|
||||
|
||||
```json
|
||||
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
|
||||
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
|
||||
```
|
||||
|
||||
```text
|
||||
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
|
||||
```
|
||||
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
|
||||
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
|
||||
environment via benchmarks:
|
||||
```
|
||||
go test -bench=.*CallerTracing
|
||||
```
|
||||
|
||||
|
||||
#### Case-sensitivity
|
||||
|
||||
@ -220,7 +251,7 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||
```go
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
|
||||
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||
"log/syslog"
|
||||
)
|
||||
@ -241,64 +272,15 @@ func init() {
|
||||
```
|
||||
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
||||
|
||||
| Hook | Description |
|
||||
| ----- | ----------- |
|
||||
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
|
||||
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
|
||||
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
|
||||
| [AzureTableHook](https://github.com/kpfaulkner/azuretablehook/) | Hook for logging to Azure Table Storage|
|
||||
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
|
||||
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
|
||||
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
|
||||
| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
|
||||
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
|
||||
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
|
||||
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
|
||||
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||
| [KafkaLogrus](https://github.com/tracer0tong/kafkalogrus) | Hook for logging to Kafka |
|
||||
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||
| [Logbeat](https://github.com/macandmia/logbeat) | Hook for logging to [Opbeat](https://opbeat.com/) |
|
||||
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
|
||||
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
|
||||
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
|
||||
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
|
||||
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
|
||||
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
|
||||
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
|
||||
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
|
||||
| [Promrus](https://github.com/weaveworks/promrus) | Expose number of log messages as [Prometheus](https://prometheus.io/) metrics |
|
||||
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
|
||||
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
|
||||
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
||||
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
|
||||
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
|
||||
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
|
||||
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
|
||||
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
|
||||
| [Telegram](https://github.com/rossmcdonald/telegram_hook) | Hook for logging errors to [Telegram](https://telegram.org/) |
|
||||
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
|
||||
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
|
||||
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
|
||||
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
|
||||
A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
|
||||
|
||||
|
||||
#### Level logging
|
||||
|
||||
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
|
||||
|
||||
```go
|
||||
log.Trace("Something very low level.")
|
||||
log.Debug("Useful debugging information.")
|
||||
log.Info("Something noteworthy happened!")
|
||||
log.Warn("You should probably take a look at this.")
|
||||
@ -370,6 +352,8 @@ The built-in logging formatters are:
|
||||
field to `true`. To force no colored output even if there is a TTY set the
|
||||
`DisableColors` field to `true`. For Windows, see
|
||||
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
||||
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
||||
truncation set the `DisableLevelTruncation` field to `true`.
|
||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
||||
@ -377,6 +361,7 @@ The built-in logging formatters are:
|
||||
Third party logging formatters:
|
||||
|
||||
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
|
||||
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
|
||||
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||
@ -493,7 +478,7 @@ logrus.RegisterExitHandler(handler)
|
||||
|
||||
#### Thread safety
|
||||
|
||||
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
|
||||
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
|
||||
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
||||
|
||||
Situation when locking is not needed includes:
|
||||
|
20
vendor/github.com/sirupsen/logrus/alt_exit_test.go
generated
vendored
20
vendor/github.com/sirupsen/logrus/alt_exit_test.go
generated
vendored
@ -6,6 +6,8 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@ -19,6 +21,9 @@ func TestRegister(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
testprog := testprogleader
|
||||
testprog = append(testprog, getPackage()...)
|
||||
testprog = append(testprog, testprogtrailer...)
|
||||
tempDir, err := ioutil.TempDir("", "test_handler")
|
||||
if err != nil {
|
||||
log.Fatalf("can't create temp dir. %q", err)
|
||||
@ -47,13 +52,24 @@ func TestHandler(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var testprog = []byte(`
|
||||
// getPackage returns the name of the current package, which makes running this
|
||||
// test in a fork simpler
|
||||
func getPackage() []byte {
|
||||
pc, _, _, _ := runtime.Caller(0)
|
||||
fullFuncName := runtime.FuncForPC(pc).Name()
|
||||
idx := strings.LastIndex(fullFuncName, ".")
|
||||
return []byte(fullFuncName[:idx]) // trim off function details
|
||||
}
|
||||
|
||||
var testprogleader = []byte(`
|
||||
// Test program for atexit, gets output file and data as arguments and writes
|
||||
// data to output file in atexit handler.
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"`)
|
||||
var testprogtrailer = []byte(
|
||||
`"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
294
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
294
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
@ -4,11 +4,30 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var bufferPool *sync.Pool
|
||||
var (
|
||||
bufferPool *sync.Pool
|
||||
|
||||
// qualified package name, cached at first use
|
||||
logrusPackage string
|
||||
|
||||
// Positions in the call stack when tracing to report the calling method
|
||||
minimumCallerDepth int
|
||||
|
||||
// Used for caller information initialisation
|
||||
callerInitOnce sync.Once
|
||||
)
|
||||
|
||||
const (
|
||||
maximumCallerDepth int = 25
|
||||
knownLogrusFrames int = 4
|
||||
)
|
||||
|
||||
func init() {
|
||||
bufferPool = &sync.Pool{
|
||||
@ -16,15 +35,18 @@ func init() {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
// start at the bottom of the stack before the package-name cache is primed
|
||||
minimumCallerDepth = 1
|
||||
}
|
||||
|
||||
// Defines the key when adding errors using WithError.
|
||||
var ErrorKey = "error"
|
||||
|
||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||
// passed around as much as you wish to avoid field duplication.
|
||||
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
|
||||
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
|
||||
// reused and passed around as much as you wish to avoid field duplication.
|
||||
type Entry struct {
|
||||
Logger *Logger
|
||||
|
||||
@ -34,22 +56,28 @@ type Entry struct {
|
||||
// Time at which the log entry was created
|
||||
Time time.Time
|
||||
|
||||
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||
Level Level
|
||||
|
||||
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
// Calling method, with package name
|
||||
Caller *runtime.Frame
|
||||
|
||||
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
|
||||
Message string
|
||||
|
||||
// When formatter is called in entry.log(), an Buffer may be set to entry
|
||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
||||
Buffer *bytes.Buffer
|
||||
|
||||
// err may contain a field formatting error
|
||||
err string
|
||||
}
|
||||
|
||||
func NewEntry(logger *Logger) *Entry {
|
||||
return &Entry{
|
||||
Logger: logger,
|
||||
// Default is three fields, give a little extra room
|
||||
Data: make(Fields, 5),
|
||||
// Default is three fields, plus one optional. Give a little extra room.
|
||||
Data: make(Fields, 6),
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,46 +108,117 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
fieldErr := entry.err
|
||||
for k, v := range fields {
|
||||
data[k] = v
|
||||
isErrField := false
|
||||
if t := reflect.TypeOf(v); t != nil {
|
||||
switch t.Kind() {
|
||||
case reflect.Func:
|
||||
isErrField = true
|
||||
case reflect.Ptr:
|
||||
isErrField = t.Elem().Kind() == reflect.Func
|
||||
}
|
||||
}
|
||||
if isErrField {
|
||||
tmp := fmt.Sprintf("can not add field %q", k)
|
||||
if fieldErr != "" {
|
||||
fieldErr = entry.err + ", " + tmp
|
||||
} else {
|
||||
fieldErr = tmp
|
||||
}
|
||||
} else {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
return &Entry{Logger: entry.Logger, Data: data}
|
||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr}
|
||||
}
|
||||
|
||||
// Overrides the time of the Entry.
|
||||
func (entry *Entry) WithTime(t time.Time) *Entry {
|
||||
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t, err: entry.err}
|
||||
}
|
||||
|
||||
// getPackageName reduces a fully qualified function name to the package name
|
||||
// There really ought to be to be a better way...
|
||||
func getPackageName(f string) string {
|
||||
for {
|
||||
lastPeriod := strings.LastIndex(f, ".")
|
||||
lastSlash := strings.LastIndex(f, "/")
|
||||
if lastPeriod > lastSlash {
|
||||
f = f[:lastPeriod]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// getCaller retrieves the name of the first non-logrus calling function
|
||||
func getCaller() *runtime.Frame {
|
||||
// Restrict the lookback frames to avoid runaway lookups
|
||||
pcs := make([]uintptr, maximumCallerDepth)
|
||||
depth := runtime.Callers(minimumCallerDepth, pcs)
|
||||
frames := runtime.CallersFrames(pcs[:depth])
|
||||
|
||||
// cache this package's fully-qualified name
|
||||
callerInitOnce.Do(func() {
|
||||
logrusPackage = getPackageName(runtime.FuncForPC(pcs[0]).Name())
|
||||
|
||||
// now that we have the cache, we can skip a minimum count of known-logrus functions
|
||||
// XXX this is dubious, the number of frames may vary store an entry in a logger interface
|
||||
minimumCallerDepth = knownLogrusFrames
|
||||
})
|
||||
|
||||
for f, again := frames.Next(); again; f, again = frames.Next() {
|
||||
pkg := getPackageName(f.Function)
|
||||
|
||||
// If the caller isn't part of this package, we're done
|
||||
if pkg != logrusPackage {
|
||||
return &f
|
||||
}
|
||||
}
|
||||
|
||||
// if we got here, we failed to find the caller's context
|
||||
return nil
|
||||
}
|
||||
|
||||
func (entry Entry) HasCaller() (has bool) {
|
||||
return entry.Logger != nil &&
|
||||
entry.Logger.ReportCaller &&
|
||||
entry.Caller != nil
|
||||
}
|
||||
|
||||
// This function is not declared with a pointer value because otherwise
|
||||
// race conditions will occur when using multiple goroutines
|
||||
func (entry Entry) log(level Level, msg string) {
|
||||
var buffer *bytes.Buffer
|
||||
entry.Time = time.Now()
|
||||
|
||||
// Default to now, but allow users to override if they want.
|
||||
//
|
||||
// We don't have to worry about polluting future calls to Entry#log()
|
||||
// with this assignment because this function is declared with a
|
||||
// non-pointer receiver.
|
||||
if entry.Time.IsZero() {
|
||||
entry.Time = time.Now()
|
||||
}
|
||||
|
||||
entry.Level = level
|
||||
entry.Message = msg
|
||||
|
||||
entry.Logger.mu.Lock()
|
||||
err := entry.Logger.Hooks.Fire(level, &entry)
|
||||
entry.Logger.mu.Unlock()
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
if entry.Logger.ReportCaller {
|
||||
entry.Caller = getCaller()
|
||||
}
|
||||
|
||||
entry.fireHooks()
|
||||
|
||||
buffer = bufferPool.Get().(*bytes.Buffer)
|
||||
buffer.Reset()
|
||||
defer bufferPool.Put(buffer)
|
||||
entry.Buffer = buffer
|
||||
serialized, err := entry.Logger.Formatter.Format(&entry)
|
||||
|
||||
entry.write()
|
||||
|
||||
entry.Buffer = nil
|
||||
if err != nil {
|
||||
entry.Logger.mu.Lock()
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
entry.Logger.mu.Unlock()
|
||||
} else {
|
||||
entry.Logger.mu.Lock()
|
||||
_, err = entry.Logger.Out.Write(serialized)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
entry.Logger.mu.Unlock()
|
||||
}
|
||||
|
||||
// To avoid Entry#log() returning a value that only would make sense for
|
||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
@ -129,26 +228,53 @@ func (entry Entry) log(level Level, msg string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||
func (entry *Entry) fireHooks() {
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
err := entry.Logger.Hooks.Fire(entry.Level, entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) write() {
|
||||
entry.Logger.mu.Lock()
|
||||
defer entry.Logger.mu.Unlock()
|
||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||
} else {
|
||||
_, err = entry.Logger.Out.Write(serialized)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Log(level Level, args ...interface{}) {
|
||||
if entry.Logger.IsLevelEnabled(level) {
|
||||
entry.log(level, fmt.Sprint(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Trace(args ...interface{}) {
|
||||
entry.Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debug(args ...interface{}) {
|
||||
entry.Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Print(args ...interface{}) {
|
||||
entry.Info(args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Info(args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warn(args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warning(args ...interface{}) {
|
||||
@ -156,37 +282,35 @@ func (entry *Entry) Warning(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Error(args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatal(args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||
}
|
||||
Exit(1)
|
||||
entry.Log(FatalLevel, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panic(args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||
}
|
||||
entry.Log(PanicLevel, args...)
|
||||
panic(fmt.Sprint(args...))
|
||||
}
|
||||
|
||||
// Entry Printf family functions
|
||||
|
||||
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
||||
entry.Log(level, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
||||
entry.Logf(TraceLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.Debug(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.Info(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
@ -194,9 +318,7 @@ func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.Warn(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
@ -204,36 +326,36 @@ func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.Error(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.Fatal(fmt.Sprintf(format, args...))
|
||||
}
|
||||
Exit(1)
|
||||
entry.Logf(FatalLevel, format, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.Panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
entry.Logf(PanicLevel, format, args...)
|
||||
}
|
||||
|
||||
// Entry Println family functions
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
if entry.Logger.level() >= DebugLevel {
|
||||
entry.Debug(entry.sprintlnn(args...))
|
||||
func (entry *Entry) Logln(level Level, args ...interface{}) {
|
||||
if entry.Logger.IsLevelEnabled(level) {
|
||||
entry.Log(level, entry.sprintlnn(args...))
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *Entry) Traceln(args ...interface{}) {
|
||||
entry.Logln(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Debugln(args ...interface{}) {
|
||||
entry.Logln(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Infoln(args ...interface{}) {
|
||||
if entry.Logger.level() >= InfoLevel {
|
||||
entry.Info(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Println(args ...interface{}) {
|
||||
@ -241,9 +363,7 @@ func (entry *Entry) Println(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Warnln(args ...interface{}) {
|
||||
if entry.Logger.level() >= WarnLevel {
|
||||
entry.Warn(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Warningln(args ...interface{}) {
|
||||
@ -251,22 +371,16 @@ func (entry *Entry) Warningln(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (entry *Entry) Errorln(args ...interface{}) {
|
||||
if entry.Logger.level() >= ErrorLevel {
|
||||
entry.Error(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||
if entry.Logger.level() >= FatalLevel {
|
||||
entry.Fatal(entry.sprintlnn(args...))
|
||||
}
|
||||
Exit(1)
|
||||
entry.Logln(FatalLevel, args...)
|
||||
entry.Logger.Exit(1)
|
||||
}
|
||||
|
||||
func (entry *Entry) Panicln(args ...interface{}) {
|
||||
if entry.Logger.level() >= PanicLevel {
|
||||
entry.Panic(entry.sprintlnn(args...))
|
||||
}
|
||||
entry.Logln(PanicLevel, args...)
|
||||
}
|
||||
|
||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||
|
64
vendor/github.com/sirupsen/logrus/entry_test.go
generated
vendored
64
vendor/github.com/sirupsen/logrus/entry_test.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -75,3 +76,66 @@ func TestEntryPanicf(t *testing.T) {
|
||||
entry := NewEntry(logger)
|
||||
entry.WithField("err", errBoom).Panicf("kaboom %v", true)
|
||||
}
|
||||
|
||||
const (
|
||||
badMessage = "this is going to panic"
|
||||
panicMessage = "this is broken"
|
||||
)
|
||||
|
||||
type panickyHook struct{}
|
||||
|
||||
func (p *panickyHook) Levels() []Level {
|
||||
return []Level{InfoLevel}
|
||||
}
|
||||
|
||||
func (p *panickyHook) Fire(entry *Entry) error {
|
||||
if entry.Message == badMessage {
|
||||
panic(panicMessage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestEntryHooksPanic(t *testing.T) {
|
||||
logger := New()
|
||||
logger.Out = &bytes.Buffer{}
|
||||
logger.Level = InfoLevel
|
||||
logger.Hooks.Add(&panickyHook{})
|
||||
|
||||
defer func() {
|
||||
p := recover()
|
||||
assert.NotNil(t, p)
|
||||
assert.Equal(t, panicMessage, p)
|
||||
|
||||
entry := NewEntry(logger)
|
||||
entry.Info("another message")
|
||||
}()
|
||||
|
||||
entry := NewEntry(logger)
|
||||
entry.Info(badMessage)
|
||||
}
|
||||
|
||||
func TestEntryWithIncorrectField(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
fn := func() {}
|
||||
|
||||
e := Entry{}
|
||||
eWithFunc := e.WithFields(Fields{"func": fn})
|
||||
eWithFuncPtr := e.WithFields(Fields{"funcPtr": &fn})
|
||||
|
||||
assert.Equal(eWithFunc.err, `can not add field "func"`)
|
||||
assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`)
|
||||
|
||||
eWithFunc = eWithFunc.WithField("not_a_func", "it is a string")
|
||||
eWithFuncPtr = eWithFuncPtr.WithField("not_a_func", "it is a string")
|
||||
|
||||
assert.Equal(eWithFunc.err, `can not add field "func"`)
|
||||
assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`)
|
||||
|
||||
eWithFunc = eWithFunc.WithTime(time.Now())
|
||||
eWithFuncPtr = eWithFuncPtr.WithTime(time.Now())
|
||||
|
||||
assert.Equal(eWithFunc.err, `can not add field "func"`)
|
||||
assert.Equal(eWithFuncPtr.err, `can not add field "funcPtr"`)
|
||||
}
|
||||
|
12
vendor/github.com/sirupsen/logrus/example_basic_test.go
generated
vendored
12
vendor/github.com/sirupsen/logrus/example_basic_test.go
generated
vendored
@ -1,16 +1,18 @@
|
||||
package logrus_test
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Example_basic() {
|
||||
var log = logrus.New()
|
||||
log.Formatter = new(logrus.JSONFormatter)
|
||||
log.Formatter = new(logrus.TextFormatter) //default
|
||||
log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors
|
||||
log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output
|
||||
log.Level = logrus.DebugLevel
|
||||
log.Level = logrus.TraceLevel
|
||||
log.Out = os.Stdout
|
||||
|
||||
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
|
||||
@ -35,6 +37,11 @@ func Example_basic() {
|
||||
}
|
||||
}()
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"number": 0,
|
||||
}).Trace("Went to the beach")
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"animal": "walrus",
|
||||
"number": 8,
|
||||
@ -60,6 +67,7 @@ func Example_basic() {
|
||||
}).Panic("It's over 9000!")
|
||||
|
||||
// Output:
|
||||
// level=trace msg="Went to the beach" animal=walrus number=0
|
||||
// level=debug msg="Started observing beach" animal=walrus number=8
|
||||
// level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||
// level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||
|
14
vendor/github.com/sirupsen/logrus/example_hook_test.go
generated
vendored
14
vendor/github.com/sirupsen/logrus/example_hook_test.go
generated
vendored
@ -1,16 +1,24 @@
|
||||
// +build !windows
|
||||
|
||||
package logrus_test
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
|
||||
"log/syslog"
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
slhooks "github.com/sirupsen/logrus/hooks/syslog"
|
||||
)
|
||||
|
||||
// An example on how to use a hook
|
||||
func Example_hook() {
|
||||
var log = logrus.New()
|
||||
log.Formatter = new(logrus.TextFormatter) // default
|
||||
log.Formatter.(*logrus.TextFormatter).DisableColors = true // remove colors
|
||||
log.Formatter.(*logrus.TextFormatter).DisableTimestamp = true // remove timestamp from test output
|
||||
log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
|
||||
if sl, err := slhooks.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, ""); err == nil {
|
||||
log.Hooks.Add(sl)
|
||||
}
|
||||
log.Out = os.Stdout
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
|
60
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
60
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
@ -2,6 +2,7 @@ package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -15,37 +16,38 @@ func StandardLogger() *Logger {
|
||||
|
||||
// SetOutput sets the standard logger output.
|
||||
func SetOutput(out io.Writer) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Out = out
|
||||
std.SetOutput(out)
|
||||
}
|
||||
|
||||
// SetFormatter sets the standard logger formatter.
|
||||
func SetFormatter(formatter Formatter) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Formatter = formatter
|
||||
std.SetFormatter(formatter)
|
||||
}
|
||||
|
||||
// SetReportCaller sets whether the standard logger will include the calling
|
||||
// method as a field.
|
||||
func SetReportCaller(include bool) {
|
||||
std.SetReportCaller(include)
|
||||
}
|
||||
|
||||
// SetLevel sets the standard logger level.
|
||||
func SetLevel(level Level) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.SetLevel(level)
|
||||
}
|
||||
|
||||
// GetLevel returns the standard logger level.
|
||||
func GetLevel() Level {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
return std.level()
|
||||
return std.GetLevel()
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
|
||||
func IsLevelEnabled(level Level) bool {
|
||||
return std.IsLevelEnabled(level)
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the standard logger hooks.
|
||||
func AddHook(hook Hook) {
|
||||
std.mu.Lock()
|
||||
defer std.mu.Unlock()
|
||||
std.Hooks.Add(hook)
|
||||
std.AddHook(hook)
|
||||
}
|
||||
|
||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||
@ -72,6 +74,20 @@ func WithFields(fields Fields) *Entry {
|
||||
return std.WithFields(fields)
|
||||
}
|
||||
|
||||
// WithTime creats an entry from the standard logger and overrides the time of
|
||||
// logs generated with it.
|
||||
//
|
||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
// or Panic on the Entry it returns.
|
||||
func WithTime(t time.Time) *Entry {
|
||||
return std.WithTime(t)
|
||||
}
|
||||
|
||||
// Trace logs a message at level Trace on the standard logger.
|
||||
func Trace(args ...interface{}) {
|
||||
std.Trace(args...)
|
||||
}
|
||||
|
||||
// Debug logs a message at level Debug on the standard logger.
|
||||
func Debug(args ...interface{}) {
|
||||
std.Debug(args...)
|
||||
@ -107,11 +123,16 @@ func Panic(args ...interface{}) {
|
||||
std.Panic(args...)
|
||||
}
|
||||
|
||||
// Fatal logs a message at level Fatal on the standard logger.
|
||||
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatal(args ...interface{}) {
|
||||
std.Fatal(args...)
|
||||
}
|
||||
|
||||
// Tracef logs a message at level Trace on the standard logger.
|
||||
func Tracef(format string, args ...interface{}) {
|
||||
std.Tracef(format, args...)
|
||||
}
|
||||
|
||||
// Debugf logs a message at level Debug on the standard logger.
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
std.Debugf(format, args...)
|
||||
@ -147,11 +168,16 @@ func Panicf(format string, args ...interface{}) {
|
||||
std.Panicf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf logs a message at level Fatal on the standard logger.
|
||||
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
std.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Traceln logs a message at level Trace on the standard logger.
|
||||
func Traceln(args ...interface{}) {
|
||||
std.Traceln(args...)
|
||||
}
|
||||
|
||||
// Debugln logs a message at level Debug on the standard logger.
|
||||
func Debugln(args ...interface{}) {
|
||||
std.Debugln(args...)
|
||||
@ -187,7 +213,7 @@ func Panicln(args ...interface{}) {
|
||||
std.Panicln(args...)
|
||||
}
|
||||
|
||||
// Fatalln logs a message at level Fatal on the standard logger.
|
||||
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
func Fatalln(args ...interface{}) {
|
||||
std.Fatalln(args...)
|
||||
}
|
||||
|
51
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
51
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
@ -2,7 +2,16 @@ package logrus
|
||||
|
||||
import "time"
|
||||
|
||||
const defaultTimestampFormat = time.RFC3339
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
defaultTimestampFormat = time.RFC3339
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
FieldKeyLogrusError = "logrus_error"
|
||||
FieldKeyFunc = "func"
|
||||
FieldKeyFile = "file"
|
||||
)
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
@ -18,7 +27,7 @@ type Formatter interface {
|
||||
Format(*Entry) ([]byte, error)
|
||||
}
|
||||
|
||||
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
|
||||
// dumping it. If this code wasn't there doing:
|
||||
//
|
||||
// logrus.WithField("level", 1).Info("hello")
|
||||
@ -30,16 +39,40 @@ type Formatter interface {
|
||||
//
|
||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
// avoid code duplication between the two default formatters.
|
||||
func prefixFieldClashes(data Fields) {
|
||||
if t, ok := data["time"]; ok {
|
||||
data["fields.time"] = t
|
||||
func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
|
||||
timeKey := fieldMap.resolve(FieldKeyTime)
|
||||
if t, ok := data[timeKey]; ok {
|
||||
data["fields."+timeKey] = t
|
||||
delete(data, timeKey)
|
||||
}
|
||||
|
||||
if m, ok := data["msg"]; ok {
|
||||
data["fields.msg"] = m
|
||||
msgKey := fieldMap.resolve(FieldKeyMsg)
|
||||
if m, ok := data[msgKey]; ok {
|
||||
data["fields."+msgKey] = m
|
||||
delete(data, msgKey)
|
||||
}
|
||||
|
||||
if l, ok := data["level"]; ok {
|
||||
data["fields.level"] = l
|
||||
levelKey := fieldMap.resolve(FieldKeyLevel)
|
||||
if l, ok := data[levelKey]; ok {
|
||||
data["fields."+levelKey] = l
|
||||
delete(data, levelKey)
|
||||
}
|
||||
|
||||
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
|
||||
if l, ok := data[logrusErrKey]; ok {
|
||||
data["fields."+logrusErrKey] = l
|
||||
delete(data, logrusErrKey)
|
||||
}
|
||||
|
||||
// If reportCaller is not set, 'func' will not conflict.
|
||||
if reportCaller {
|
||||
funcKey := fieldMap.resolve(FieldKeyFunc)
|
||||
if l, ok := data[funcKey]; ok {
|
||||
data["fields."+funcKey] = l
|
||||
}
|
||||
fileKey := fieldMap.resolve(FieldKeyFile)
|
||||
if l, ok := data[fileKey]; ok {
|
||||
data["fields."+fileKey] = l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
50
vendor/github.com/sirupsen/logrus/hook_test.go
generated
vendored
50
vendor/github.com/sirupsen/logrus/hook_test.go
generated
vendored
@ -1,10 +1,16 @@
|
||||
package logrus
|
||||
package logrus_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
. "github.com/sirupsen/logrus"
|
||||
. "github.com/sirupsen/logrus/internal/testutils"
|
||||
)
|
||||
|
||||
type TestHook struct {
|
||||
@ -18,6 +24,7 @@ func (hook *TestHook) Fire(entry *Entry) error {
|
||||
|
||||
func (hook *TestHook) Levels() []Level {
|
||||
return []Level{
|
||||
TraceLevel,
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
@ -50,6 +57,7 @@ func (hook *ModifyHook) Fire(entry *Entry) error {
|
||||
|
||||
func (hook *ModifyHook) Levels() []Level {
|
||||
return []Level{
|
||||
TraceLevel,
|
||||
DebugLevel,
|
||||
InfoLevel,
|
||||
WarnLevel,
|
||||
@ -85,6 +93,46 @@ func TestCanFireMultipleHooks(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
type SingleLevelModifyHook struct {
|
||||
ModifyHook
|
||||
}
|
||||
|
||||
func (h *SingleLevelModifyHook) Levels() []Level {
|
||||
return []Level{InfoLevel}
|
||||
}
|
||||
|
||||
func TestHookEntryIsPristine(t *testing.T) {
|
||||
l := New()
|
||||
b := &bytes.Buffer{}
|
||||
l.Formatter = &JSONFormatter{}
|
||||
l.Out = b
|
||||
l.AddHook(&SingleLevelModifyHook{})
|
||||
|
||||
l.Error("error message")
|
||||
data := map[string]string{}
|
||||
err := json.Unmarshal(b.Bytes(), &data)
|
||||
require.NoError(t, err)
|
||||
_, ok := data["wow"]
|
||||
require.False(t, ok)
|
||||
b.Reset()
|
||||
|
||||
l.Info("error message")
|
||||
data = map[string]string{}
|
||||
err = json.Unmarshal(b.Bytes(), &data)
|
||||
require.NoError(t, err)
|
||||
_, ok = data["wow"]
|
||||
require.True(t, ok)
|
||||
b.Reset()
|
||||
|
||||
l.Error("error message")
|
||||
data = map[string]string{}
|
||||
err = json.Unmarshal(b.Bytes(), &data)
|
||||
require.NoError(t, err)
|
||||
_, ok = data["wow"]
|
||||
require.False(t, ok)
|
||||
b.Reset()
|
||||
}
|
||||
|
||||
type ErrorHook struct {
|
||||
Fired bool
|
||||
}
|
||||
|
2
vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
@ -43,7 +43,7 @@ func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
||||
return hook.Writer.Warning(line)
|
||||
case logrus.InfoLevel:
|
||||
return hook.Writer.Info(line)
|
||||
case logrus.DebugLevel:
|
||||
case logrus.DebugLevel, logrus.TraceLevel:
|
||||
return hook.Writer.Debug(line)
|
||||
default:
|
||||
return nil
|
||||
|
2
vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
@ -1,3 +1,5 @@
|
||||
// +build !windows,!nacl,!plan9
|
||||
|
||||
package syslog
|
||||
|
||||
import (
|
||||
|
15
vendor/github.com/sirupsen/logrus/hooks/test/test.go
generated
vendored
15
vendor/github.com/sirupsen/logrus/hooks/test/test.go
generated
vendored
@ -15,7 +15,7 @@ type Hook struct {
|
||||
// Entries is an array of all entries that have been received by this hook.
|
||||
// For safe access, use the AllEntries() method, rather than reading this
|
||||
// value directly.
|
||||
Entries []*logrus.Entry
|
||||
Entries []logrus.Entry
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ func NewNullLogger() (*logrus.Logger, *Hook) {
|
||||
func (t *Hook) Fire(e *logrus.Entry) error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.Entries = append(t.Entries, e)
|
||||
t.Entries = append(t.Entries, *e)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -68,9 +68,7 @@ func (t *Hook) LastEntry() *logrus.Entry {
|
||||
if i < 0 {
|
||||
return nil
|
||||
}
|
||||
// Make a copy, for safety
|
||||
e := *t.Entries[i]
|
||||
return &e
|
||||
return &t.Entries[i]
|
||||
}
|
||||
|
||||
// AllEntries returns all entries that were logged.
|
||||
@ -79,10 +77,9 @@ func (t *Hook) AllEntries() []*logrus.Entry {
|
||||
defer t.mu.RUnlock()
|
||||
// Make a copy so the returned value won't race with future log requests
|
||||
entries := make([]*logrus.Entry, len(t.Entries))
|
||||
for i, entry := range t.Entries {
|
||||
for i := 0; i < len(t.Entries); i++ {
|
||||
// Make a copy, for safety
|
||||
e := *entry
|
||||
entries[i] = &e
|
||||
entries[i] = &t.Entries[i]
|
||||
}
|
||||
return entries
|
||||
}
|
||||
@ -91,5 +88,5 @@ func (t *Hook) AllEntries() []*logrus.Entry {
|
||||
func (t *Hook) Reset() {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.Entries = make([]*logrus.Entry, 0)
|
||||
t.Entries = make([]logrus.Entry, 0)
|
||||
}
|
||||
|
50
vendor/github.com/sirupsen/logrus/hooks/test/test_test.go
generated
vendored
50
vendor/github.com/sirupsen/logrus/hooks/test/test_test.go
generated
vendored
@ -1,14 +1,16 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAllHooks(t *testing.T) {
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
logger, hook := NewNullLogger()
|
||||
@ -35,5 +37,49 @@ func TestAllHooks(t *testing.T) {
|
||||
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||
assert.Equal(1, len(hook.Entries))
|
||||
|
||||
}
|
||||
|
||||
func TestLoggingWithHooksRace(t *testing.T) {
|
||||
|
||||
rand.Seed(time.Now().Unix())
|
||||
unlocker := rand.Int() % 100
|
||||
|
||||
assert := assert.New(t)
|
||||
logger, hook := NewNullLogger()
|
||||
|
||||
var wgOne, wgAll sync.WaitGroup
|
||||
wgOne.Add(1)
|
||||
wgAll.Add(100)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
go func(i int) {
|
||||
logger.Info("info")
|
||||
wgAll.Done()
|
||||
if i == unlocker {
|
||||
wgOne.Done()
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wgOne.Wait()
|
||||
|
||||
assert.Equal(logrus.InfoLevel, hook.LastEntry().Level)
|
||||
assert.Equal("info", hook.LastEntry().Message)
|
||||
|
||||
wgAll.Wait()
|
||||
|
||||
entries := hook.AllEntries()
|
||||
assert.Equal(100, len(entries))
|
||||
}
|
||||
|
||||
func TestFatalWithAlternateExit(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
logger, hook := NewNullLogger()
|
||||
logger.ExitFunc = func(code int) {}
|
||||
|
||||
logger.Fatal("something went very wrong")
|
||||
assert.Equal(logrus.FatalLevel, hook.LastEntry().Level)
|
||||
assert.Equal("something went very wrong", hook.LastEntry().Message)
|
||||
assert.Equal(1, len(hook.Entries))
|
||||
}
|
||||
|
54
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
54
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
@ -10,13 +11,6 @@ type fieldKey string
|
||||
// FieldMap allows customization of the key names for default fields.
|
||||
type FieldMap map[fieldKey]string
|
||||
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
FieldKeyTime = "time"
|
||||
)
|
||||
|
||||
func (f FieldMap) resolve(key fieldKey) string {
|
||||
if k, ok := f[key]; ok {
|
||||
return k
|
||||
@ -33,21 +27,28 @@ type JSONFormatter struct {
|
||||
// DisableTimestamp allows disabling automatic timestamps in output
|
||||
DisableTimestamp bool
|
||||
|
||||
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
|
||||
DataKey string
|
||||
|
||||
// FieldMap allows users to customize the names of keys for default fields.
|
||||
// As an example:
|
||||
// formatter := &JSONFormatter{
|
||||
// FieldMap: FieldMap{
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyLevel: "@level",
|
||||
// FieldKeyMsg: "@message",
|
||||
// FieldKeyMsg: "@message",
|
||||
// FieldKeyFunc: "@caller",
|
||||
// },
|
||||
// }
|
||||
FieldMap FieldMap
|
||||
|
||||
// PrettyPrint will indent all json logs
|
||||
PrettyPrint bool
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+3)
|
||||
data := make(Fields, len(entry.Data)+4)
|
||||
for k, v := range entry.Data {
|
||||
switch v := v.(type) {
|
||||
case error:
|
||||
@ -58,22 +59,47 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data[k] = v
|
||||
}
|
||||
}
|
||||
prefixFieldClashes(data)
|
||||
|
||||
if f.DataKey != "" {
|
||||
newData := make(Fields, 4)
|
||||
newData[f.DataKey] = data
|
||||
data = newData
|
||||
}
|
||||
|
||||
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
|
||||
if entry.err != "" {
|
||||
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
|
||||
}
|
||||
if !f.DisableTimestamp {
|
||||
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
||||
}
|
||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
||||
if entry.HasCaller() {
|
||||
data[f.FieldMap.resolve(FieldKeyFunc)] = entry.Caller.Function
|
||||
data[f.FieldMap.resolve(FieldKeyFile)] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||
}
|
||||
|
||||
serialized, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(b)
|
||||
if f.PrettyPrint {
|
||||
encoder.SetIndent("", " ")
|
||||
}
|
||||
if err := encoder.Encode(data); err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||
}
|
||||
return append(serialized, '\n'), nil
|
||||
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
147
vendor/github.com/sirupsen/logrus/json_formatter_test.go
generated
vendored
147
vendor/github.com/sirupsen/logrus/json_formatter_test.go
generated
vendored
@ -3,6 +3,8 @@ package logrus
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@ -106,6 +108,102 @@ func TestFieldClashWithLevel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldClashWithRemappedFields(t *testing.T) {
|
||||
formatter := &JSONFormatter{
|
||||
FieldMap: FieldMap{
|
||||
FieldKeyTime: "@timestamp",
|
||||
FieldKeyLevel: "@level",
|
||||
FieldKeyMsg: "@message",
|
||||
},
|
||||
}
|
||||
|
||||
b, err := formatter.Format(WithFields(Fields{
|
||||
"@timestamp": "@timestamp",
|
||||
"@level": "@level",
|
||||
"@message": "@message",
|
||||
"timestamp": "timestamp",
|
||||
"level": "level",
|
||||
"msg": "msg",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
for _, field := range []string{"timestamp", "level", "msg"} {
|
||||
if entry[field] != field {
|
||||
t.Errorf("Expected field %v to be untouched; got %v", field, entry[field])
|
||||
}
|
||||
|
||||
remappedKey := fmt.Sprintf("fields.%s", field)
|
||||
if remapped, ok := entry[remappedKey]; ok {
|
||||
t.Errorf("Expected %s to be empty; got %v", remappedKey, remapped)
|
||||
}
|
||||
}
|
||||
|
||||
for _, field := range []string{"@timestamp", "@level", "@message"} {
|
||||
if entry[field] == field {
|
||||
t.Errorf("Expected field %v to be mapped to an Entry value", field)
|
||||
}
|
||||
|
||||
remappedKey := fmt.Sprintf("fields.%s", field)
|
||||
if remapped, ok := entry[remappedKey]; ok {
|
||||
if remapped != field {
|
||||
t.Errorf("Expected field %v to be copied to %s; got %v", field, remappedKey, remapped)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected field %v to be copied to %s; was absent", field, remappedKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldsInNestedDictionary(t *testing.T) {
|
||||
formatter := &JSONFormatter{
|
||||
DataKey: "args",
|
||||
}
|
||||
|
||||
logEntry := WithFields(Fields{
|
||||
"level": "level",
|
||||
"test": "test",
|
||||
})
|
||||
logEntry.Level = InfoLevel
|
||||
|
||||
b, err := formatter.Format(logEntry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
args := entry["args"].(map[string]interface{})
|
||||
|
||||
for _, field := range []string{"test", "level"} {
|
||||
if value, present := args[field]; !present || value != field {
|
||||
t.Errorf("Expected field %v to be present under 'args'; untouched", field)
|
||||
}
|
||||
}
|
||||
|
||||
for _, field := range []string{"test", "fields.level"} {
|
||||
if _, present := entry[field]; present {
|
||||
t.Errorf("Expected field %v not to be present at top level", field)
|
||||
}
|
||||
}
|
||||
|
||||
// with nested object, "level" shouldn't clash
|
||||
if entry["level"] != "info" {
|
||||
t.Errorf("Expected 'level' field to contain 'info'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONEntryEndsWithNewline(t *testing.T) {
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
@ -170,6 +268,55 @@ func TestJSONTimeKey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldDoesNotClashWithCaller(t *testing.T) {
|
||||
SetReportCaller(false)
|
||||
formatter := &JSONFormatter{}
|
||||
|
||||
b, err := formatter.Format(WithField("func", "howdy pardner"))
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
if entry["func"] != "howdy pardner" {
|
||||
t.Fatal("func field replaced when ReportCaller=false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldClashWithCaller(t *testing.T) {
|
||||
SetReportCaller(true)
|
||||
formatter := &JSONFormatter{}
|
||||
e := WithField("func", "howdy pardner")
|
||||
e.Caller = &runtime.Frame{Function: "somefunc"}
|
||||
b, err := formatter.Format(e)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
entry := make(map[string]interface{})
|
||||
err = json.Unmarshal(b, &entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to unmarshal formatted entry: ", err)
|
||||
}
|
||||
|
||||
if entry["fields.func"] != "howdy pardner" {
|
||||
t.Fatalf("fields.func not set to original func field when ReportCaller=true (got '%s')",
|
||||
entry["fields.func"])
|
||||
}
|
||||
|
||||
if entry["func"] != "somefunc" {
|
||||
t.Fatalf("func not set as expected when ReportCaller=true (got '%s')",
|
||||
entry["func"])
|
||||
}
|
||||
|
||||
SetReportCaller(false) // return to default value
|
||||
}
|
||||
|
||||
func TestJSONDisableTimestamp(t *testing.T) {
|
||||
formatter := &JSONFormatter{
|
||||
DisableTimestamp: true,
|
||||
|
230
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
230
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
@ -5,12 +5,13 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Logger struct {
|
||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||
// something more adventorous, such as logging to Kafka.
|
||||
// something more adventurous, such as logging to Kafka.
|
||||
Out io.Writer
|
||||
// Hooks for the logger instance. These allow firing events based on logging
|
||||
// levels and log entries. For example, to send errors to an error tracking
|
||||
@ -23,6 +24,10 @@ type Logger struct {
|
||||
// own that implements the `Formatter` interface, see the `README` or included
|
||||
// formatters for examples.
|
||||
Formatter Formatter
|
||||
|
||||
// Flag for whether to log caller info (off by default)
|
||||
ReportCaller bool
|
||||
|
||||
// The logging level the logger should log at. This is typically (and defaults
|
||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
// logged.
|
||||
@ -31,8 +36,12 @@ type Logger struct {
|
||||
mu MutexWrap
|
||||
// Reusable empty entry
|
||||
entryPool sync.Pool
|
||||
// Function to exit the application, defaults to `os.Exit()`
|
||||
ExitFunc exitFunc
|
||||
}
|
||||
|
||||
type exitFunc func(int)
|
||||
|
||||
type MutexWrap struct {
|
||||
lock sync.Mutex
|
||||
disabled bool
|
||||
@ -68,10 +77,12 @@ func (mw *MutexWrap) Disable() {
|
||||
// It's recommended to make this a global instance called `log`.
|
||||
func New() *Logger {
|
||||
return &Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: new(TextFormatter),
|
||||
Hooks: make(LevelHooks),
|
||||
Level: InfoLevel,
|
||||
Out: os.Stderr,
|
||||
Formatter: new(TextFormatter),
|
||||
Hooks: make(LevelHooks),
|
||||
Level: InfoLevel,
|
||||
ExitFunc: os.Exit,
|
||||
ReportCaller: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,11 +95,12 @@ func (logger *Logger) newEntry() *Entry {
|
||||
}
|
||||
|
||||
func (logger *Logger) releaseEntry(entry *Entry) {
|
||||
entry.Data = map[string]interface{}{}
|
||||
logger.entryPool.Put(entry)
|
||||
}
|
||||
|
||||
// Adds a field to the log entry, note that it doesn't log until you call
|
||||
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
|
||||
// If you want multiple fields, use `WithFields`.
|
||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||
entry := logger.newEntry()
|
||||
@ -112,20 +124,31 @@ func (logger *Logger) WithError(err error) *Entry {
|
||||
return entry.WithError(err)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
// Overrides the time of the log entry.
|
||||
func (logger *Logger) WithTime(t time.Time) *Entry {
|
||||
entry := logger.newEntry()
|
||||
defer logger.releaseEntry(entry)
|
||||
return entry.WithTime(t)
|
||||
}
|
||||
|
||||
func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugf(format, args...)
|
||||
entry.Logf(level, format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Tracef(format string, args ...interface{}) {
|
||||
logger.Logf(TraceLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||
logger.Logf(DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Infof(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logf(InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
@ -135,60 +158,44 @@ func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logf(WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logf(ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalf(format, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
Exit(1)
|
||||
logger.Logf(FatalLevel, format, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
logger.Logf(PanicLevel, format, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Log(level Level, args ...interface{}) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicf(format, args...)
|
||||
entry.Log(level, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Trace(args ...interface{}) {
|
||||
logger.Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debug(args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Debug(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Info(args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Info(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Print(args ...interface{}) {
|
||||
@ -198,60 +205,44 @@ func (logger *Logger) Print(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warn(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warning(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warn(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Warn(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Error(args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Error(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatal(args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatal(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
Exit(1)
|
||||
logger.Log(FatalLevel, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panic(args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
logger.Log(PanicLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Logln(level Level, args ...interface{}) {
|
||||
if logger.IsLevelEnabled(level) {
|
||||
entry := logger.newEntry()
|
||||
entry.Panic(args...)
|
||||
entry.Logln(level, args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (logger *Logger) Traceln(args ...interface{}) {
|
||||
logger.Logln(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Debugln(args ...interface{}) {
|
||||
if logger.level() >= DebugLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Debugln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Infoln(args ...interface{}) {
|
||||
if logger.level() >= InfoLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Infoln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Println(args ...interface{}) {
|
||||
@ -261,44 +252,32 @@ func (logger *Logger) Println(args ...interface{}) {
|
||||
}
|
||||
|
||||
func (logger *Logger) Warnln(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Warningln(args ...interface{}) {
|
||||
if logger.level() >= WarnLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Warnln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Warn(args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Errorln(args ...interface{}) {
|
||||
if logger.level() >= ErrorLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Errorln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
logger.Logln(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||
if logger.level() >= FatalLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Fatalln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
}
|
||||
Exit(1)
|
||||
logger.Logln(FatalLevel, args...)
|
||||
logger.Exit(1)
|
||||
}
|
||||
|
||||
func (logger *Logger) Panicln(args ...interface{}) {
|
||||
if logger.level() >= PanicLevel {
|
||||
entry := logger.newEntry()
|
||||
entry.Panicln(args...)
|
||||
logger.releaseEntry(entry)
|
||||
logger.Logln(PanicLevel, args...)
|
||||
}
|
||||
|
||||
func (logger *Logger) Exit(code int) {
|
||||
runHandlers()
|
||||
if logger.ExitFunc == nil {
|
||||
logger.ExitFunc = os.Exit
|
||||
}
|
||||
logger.ExitFunc(code)
|
||||
}
|
||||
|
||||
//When file is opened with appending mode, it's safe to
|
||||
@ -312,12 +291,53 @@ func (logger *Logger) level() Level {
|
||||
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
||||
}
|
||||
|
||||
// SetLevel sets the logger level.
|
||||
func (logger *Logger) SetLevel(level Level) {
|
||||
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
||||
}
|
||||
|
||||
// GetLevel returns the logger level.
|
||||
func (logger *Logger) GetLevel() Level {
|
||||
return logger.level()
|
||||
}
|
||||
|
||||
// AddHook adds a hook to the logger hooks.
|
||||
func (logger *Logger) AddHook(hook Hook) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Hooks.Add(hook)
|
||||
}
|
||||
|
||||
// IsLevelEnabled checks if the log level of the logger is greater than the level param
|
||||
func (logger *Logger) IsLevelEnabled(level Level) bool {
|
||||
return logger.level() >= level
|
||||
}
|
||||
|
||||
// SetFormatter sets the logger formatter.
|
||||
func (logger *Logger) SetFormatter(formatter Formatter) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Formatter = formatter
|
||||
}
|
||||
|
||||
// SetOutput sets the logger output.
|
||||
func (logger *Logger) SetOutput(output io.Writer) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.Out = output
|
||||
}
|
||||
|
||||
func (logger *Logger) SetReportCaller(reportCaller bool) {
|
||||
logger.mu.Lock()
|
||||
defer logger.mu.Unlock()
|
||||
logger.ReportCaller = reportCaller
|
||||
}
|
||||
|
||||
// ReplaceHooks replaces the logger hooks and returns the old ones
|
||||
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
||||
logger.mu.Lock()
|
||||
oldHooks := logger.Hooks
|
||||
logger.Hooks = hooks
|
||||
logger.mu.Unlock()
|
||||
return oldHooks
|
||||
}
|
||||
|
24
vendor/github.com/sirupsen/logrus/logger_bench_test.go
generated
vendored
24
vendor/github.com/sirupsen/logrus/logger_bench_test.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
@ -59,3 +60,26 @@ func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fi
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkLoggerJSONFormatter(b *testing.B) {
|
||||
doLoggerBenchmarkWithFormatter(b, &JSONFormatter{})
|
||||
}
|
||||
|
||||
func BenchmarkLoggerTextFormatter(b *testing.B) {
|
||||
doLoggerBenchmarkWithFormatter(b, &TextFormatter{})
|
||||
}
|
||||
|
||||
func doLoggerBenchmarkWithFormatter(b *testing.B, f Formatter) {
|
||||
b.SetParallelism(100)
|
||||
log := New()
|
||||
log.Formatter = f
|
||||
log.Out = ioutil.Discard
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
log.
|
||||
WithField("foo1", "bar1").
|
||||
WithField("foo2", "bar2").
|
||||
Info("this is a dummy log")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
75
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
75
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
@ -14,22 +14,11 @@ type Level uint32
|
||||
|
||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||
func (level Level) String() string {
|
||||
switch level {
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warning"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
if b, err := level.MarshalText(); err == nil {
|
||||
return string(b)
|
||||
} else {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
@ -47,12 +36,47 @@ func ParseLevel(lvl string) (Level, error) {
|
||||
return InfoLevel, nil
|
||||
case "debug":
|
||||
return DebugLevel, nil
|
||||
case "trace":
|
||||
return TraceLevel, nil
|
||||
}
|
||||
|
||||
var l Level
|
||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (level *Level) UnmarshalText(text []byte) error {
|
||||
l, err := ParseLevel(string(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*level = Level(l)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (level Level) MarshalText() ([]byte, error) {
|
||||
switch level {
|
||||
case TraceLevel:
|
||||
return []byte("trace"), nil
|
||||
case DebugLevel:
|
||||
return []byte("debug"), nil
|
||||
case InfoLevel:
|
||||
return []byte("info"), nil
|
||||
case WarnLevel:
|
||||
return []byte("warning"), nil
|
||||
case ErrorLevel:
|
||||
return []byte("error"), nil
|
||||
case FatalLevel:
|
||||
return []byte("fatal"), nil
|
||||
case PanicLevel:
|
||||
return []byte("panic"), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("not a valid lorus level %q", level)
|
||||
}
|
||||
|
||||
// A constant exposing all logging levels
|
||||
var AllLevels = []Level{
|
||||
PanicLevel,
|
||||
@ -61,6 +85,7 @@ var AllLevels = []Level{
|
||||
WarnLevel,
|
||||
InfoLevel,
|
||||
DebugLevel,
|
||||
TraceLevel,
|
||||
}
|
||||
|
||||
// These are the different logging levels. You can set the logging level to log
|
||||
@ -69,7 +94,7 @@ const (
|
||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
// message passed to Debug, Info, ...
|
||||
PanicLevel Level = iota
|
||||
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||
// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
|
||||
// logging level is set to Panic.
|
||||
FatalLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
@ -82,6 +107,8 @@ const (
|
||||
InfoLevel
|
||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
DebugLevel
|
||||
// TraceLevel level. Designates finer-grained informational events than the Debug.
|
||||
TraceLevel
|
||||
)
|
||||
|
||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||
@ -140,4 +167,20 @@ type FieldLogger interface {
|
||||
Errorln(args ...interface{})
|
||||
Fatalln(args ...interface{})
|
||||
Panicln(args ...interface{})
|
||||
|
||||
// IsDebugEnabled() bool
|
||||
// IsInfoEnabled() bool
|
||||
// IsWarnEnabled() bool
|
||||
// IsErrorEnabled() bool
|
||||
// IsFatalEnabled() bool
|
||||
// IsPanicEnabled() bool
|
||||
}
|
||||
|
||||
// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
|
||||
// here for consistancy. Do not use. Use Logger or Entry instead.
|
||||
type Ext1FieldLogger interface {
|
||||
FieldLogger
|
||||
Tracef(format string, args ...interface{})
|
||||
Trace(args ...interface{})
|
||||
Traceln(args ...interface{})
|
||||
}
|
||||
|
434
vendor/github.com/sirupsen/logrus/logrus_test.go
generated
vendored
434
vendor/github.com/sirupsen/logrus/logrus_test.go
generated
vendored
@ -1,67 +1,95 @@
|
||||
package logrus
|
||||
package logrus_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
. "github.com/sirupsen/logrus"
|
||||
. "github.com/sirupsen/logrus/internal/testutils"
|
||||
)
|
||||
|
||||
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
|
||||
// TestReportCaller verifies that when ReportCaller is set, the 'func' field
|
||||
// is added, and when it is unset it is not set or modified
|
||||
// Verify that functions within the Logrus package aren't considered when
|
||||
// discovering the caller.
|
||||
func TestReportCallerWhenConfigured(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.ReportCaller = false
|
||||
log.Print("testNoCaller")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, "testNoCaller", fields["msg"])
|
||||
assert.Equal(t, "info", fields["level"])
|
||||
assert.Equal(t, nil, fields["func"])
|
||||
})
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.ReportCaller = true
|
||||
log.Print("testWithCaller")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, "testWithCaller", fields["msg"])
|
||||
assert.Equal(t, "info", fields["level"])
|
||||
assert.Equal(t,
|
||||
"github.com/sirupsen/logrus_test.TestReportCallerWhenConfigured.func3", fields["func"])
|
||||
})
|
||||
}
|
||||
|
||||
func logSomething(t *testing.T, message string) Fields {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
logger.ReportCaller = true
|
||||
|
||||
log(logger)
|
||||
entry := logger.WithFields(Fields{
|
||||
"foo": "bar",
|
||||
})
|
||||
|
||||
entry.Info(message)
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assertions(fields)
|
||||
return fields
|
||||
}
|
||||
|
||||
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
|
||||
var buffer bytes.Buffer
|
||||
// TestReportCallerHelperDirect - verify reference when logging from a regular function
|
||||
func TestReportCallerHelperDirect(t *testing.T) {
|
||||
fields := logSomething(t, "direct")
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = &TextFormatter{
|
||||
DisableColors: true,
|
||||
}
|
||||
assert.Equal(t, "direct", fields["msg"])
|
||||
assert.Equal(t, "info", fields["level"])
|
||||
assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"])
|
||||
}
|
||||
|
||||
log(logger)
|
||||
// TestReportCallerHelperDirect - verify reference when logging from a function called via pointer
|
||||
func TestReportCallerHelperViaPointer(t *testing.T) {
|
||||
fptr := logSomething
|
||||
fields := fptr(t, "via pointer")
|
||||
|
||||
fields := make(map[string]string)
|
||||
for _, kv := range strings.Split(buffer.String(), " ") {
|
||||
if !strings.Contains(kv, "=") {
|
||||
continue
|
||||
}
|
||||
kvArr := strings.Split(kv, "=")
|
||||
key := strings.TrimSpace(kvArr[0])
|
||||
val := kvArr[1]
|
||||
if kvArr[1][0] == '"' {
|
||||
var err error
|
||||
val, err = strconv.Unquote(val)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
fields[key] = val
|
||||
}
|
||||
assertions(fields)
|
||||
assert.Equal(t, "via pointer", fields["msg"])
|
||||
assert.Equal(t, "info", fields["level"])
|
||||
assert.Regexp(t, "github.com/.*/logrus_test.logSomething", fields["func"])
|
||||
}
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Print("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
assert.Equal(t, "test", fields["msg"])
|
||||
assert.Equal(t, "info", fields["level"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -69,8 +97,8 @@ func TestInfo(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
assert.Equal(t, "test", fields["msg"])
|
||||
assert.Equal(t, "info", fields["level"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -78,8 +106,17 @@ func TestWarn(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Warn("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["level"], "warning")
|
||||
assert.Equal(t, "test", fields["msg"])
|
||||
assert.Equal(t, "warning", fields["level"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Log(WarnLevel, "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, "test", fields["msg"])
|
||||
assert.Equal(t, "warning", fields["level"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -87,7 +124,7 @@ func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test test")
|
||||
assert.Equal(t, "test test", fields["msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -95,7 +132,7 @@ func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test 10")
|
||||
assert.Equal(t, "test 10", fields["msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -103,7 +140,7 @@ func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
assert.Equal(t, "10 10", fields["msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -111,7 +148,7 @@ func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Infoln(10, 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "10 10")
|
||||
assert.Equal(t, "10 10", fields["msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -119,7 +156,7 @@ func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", 10)
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test10")
|
||||
assert.Equal(t, "test10", fields["msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -127,7 +164,7 @@ func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.Info("test", "test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "testtest")
|
||||
assert.Equal(t, "testtest", fields["msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -165,7 +202,7 @@ func TestUserSuppliedFieldDoesNotOverwriteDefaults(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, "test", fields["msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -173,8 +210,8 @@ func TestUserSuppliedMsgFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("msg", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["msg"], "test")
|
||||
assert.Equal(t, fields["fields.msg"], "hello")
|
||||
assert.Equal(t, "test", fields["msg"])
|
||||
assert.Equal(t, "hello", fields["fields.msg"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -182,7 +219,7 @@ func TestUserSuppliedTimeFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("time", "hello").Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["fields.time"], "hello")
|
||||
assert.Equal(t, "hello", fields["fields.time"])
|
||||
})
|
||||
}
|
||||
|
||||
@ -190,8 +227,8 @@ func TestUserSuppliedLevelFieldHasPrefix(t *testing.T) {
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("level", 1).Info("test")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["level"], "info")
|
||||
assert.Equal(t, fields["fields.level"], 1.0) // JSON has floats only
|
||||
assert.Equal(t, "info", fields["level"])
|
||||
assert.Equal(t, 1.0, fields["fields.level"]) // JSON has floats only
|
||||
})
|
||||
}
|
||||
|
||||
@ -209,6 +246,65 @@ func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithTimeShouldOverrideTime(t *testing.T) {
|
||||
now := time.Now().Add(24 * time.Hour)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithTime(now).Info("foobar")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["time"], now.Format(time.RFC3339))
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithTimeShouldNotOverrideFields(t *testing.T) {
|
||||
now := time.Now().Add(24 * time.Hour)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithField("herp", "derp").WithTime(now).Info("blah")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["time"], now.Format(time.RFC3339))
|
||||
assert.Equal(t, fields["herp"], "derp")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWithFieldShouldNotOverrideTime(t *testing.T) {
|
||||
now := time.Now().Add(24 * time.Hour)
|
||||
|
||||
LogAndAssertJSON(t, func(log *Logger) {
|
||||
log.WithTime(now).WithField("herp", "derp").Info("blah")
|
||||
}, func(fields Fields) {
|
||||
assert.Equal(t, fields["time"], now.Format(time.RFC3339))
|
||||
assert.Equal(t, fields["herp"], "derp")
|
||||
})
|
||||
}
|
||||
|
||||
func TestTimeOverrideMultipleLogs(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
var firstFields, secondFields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
formatter := new(JSONFormatter)
|
||||
formatter.TimestampFormat = time.StampMilli
|
||||
logger.Formatter = formatter
|
||||
|
||||
llog := logger.WithField("herp", "derp")
|
||||
llog.Info("foo")
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &firstFields)
|
||||
assert.NoError(t, err, "should have decoded first message")
|
||||
|
||||
buffer.Reset()
|
||||
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
llog.Info("bar")
|
||||
|
||||
err = json.Unmarshal(buffer.Bytes(), &secondFields)
|
||||
assert.NoError(t, err, "should have decoded second message")
|
||||
|
||||
assert.NotEqual(t, firstFields["time"], secondFields["time"], "timestamps should not be equal")
|
||||
}
|
||||
|
||||
func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
|
||||
|
||||
var buffer bytes.Buffer
|
||||
@ -235,13 +331,119 @@ func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded second message")
|
||||
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||
assert.Equal(t, fields["msg"], "omg it is!")
|
||||
assert.Equal(t, fields["context"], "eating raw fish")
|
||||
assert.Equal(t, "omg it is!", fields["msg"])
|
||||
assert.Equal(t, "eating raw fish", fields["context"])
|
||||
assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
|
||||
|
||||
}
|
||||
|
||||
func TestNestedLoggingReportsCorrectCaller(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
var fields Fields
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
logger.ReportCaller = true
|
||||
|
||||
llog := logger.WithField("context", "eating raw fish")
|
||||
|
||||
llog.Info("looks delicious")
|
||||
_, _, line, _ := runtime.Caller(0)
|
||||
|
||||
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||
require.NoError(t, err, "should have decoded first message")
|
||||
assert.Equal(t, 6, len(fields), "should have msg/time/level/func/context fields")
|
||||
assert.Equal(t, "looks delicious", fields["msg"])
|
||||
assert.Equal(t, "eating raw fish", fields["context"])
|
||||
assert.Equal(t,
|
||||
"github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"])
|
||||
cwd, err := os.Getwd()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, filepath.ToSlash(fmt.Sprintf("%s/logrus_test.go:%d", cwd, line-1)), filepath.ToSlash(fields["file"].(string)))
|
||||
|
||||
buffer.Reset()
|
||||
|
||||
logger.WithFields(Fields{
|
||||
"Clyde": "Stubblefield",
|
||||
}).WithFields(Fields{
|
||||
"Jab'o": "Starks",
|
||||
}).WithFields(Fields{
|
||||
"uri": "https://www.youtube.com/watch?v=V5DTznu-9v0",
|
||||
}).WithFields(Fields{
|
||||
"func": "y drummer",
|
||||
}).WithFields(Fields{
|
||||
"James": "Brown",
|
||||
}).Print("The hardest workin' man in show business")
|
||||
_, _, line, _ = runtime.Caller(0)
|
||||
|
||||
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||
assert.NoError(t, err, "should have decoded second message")
|
||||
assert.Equal(t, 11, len(fields), "should have all builtin fields plus foo,bar,baz,...")
|
||||
assert.Equal(t, "Stubblefield", fields["Clyde"])
|
||||
assert.Equal(t, "Starks", fields["Jab'o"])
|
||||
assert.Equal(t, "https://www.youtube.com/watch?v=V5DTznu-9v0", fields["uri"])
|
||||
assert.Equal(t, "y drummer", fields["fields.func"])
|
||||
assert.Equal(t, "Brown", fields["James"])
|
||||
assert.Equal(t, "The hardest workin' man in show business", fields["msg"])
|
||||
assert.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
|
||||
assert.Equal(t,
|
||||
"github.com/sirupsen/logrus_test.TestNestedLoggingReportsCorrectCaller", fields["func"])
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, filepath.ToSlash(fmt.Sprintf("%s/logrus_test.go:%d", cwd, line-1)), filepath.ToSlash(fields["file"].(string)))
|
||||
|
||||
logger.ReportCaller = false // return to default value
|
||||
}
|
||||
|
||||
func logLoop(iterations int, reportCaller bool) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
logger := New()
|
||||
logger.Out = &buffer
|
||||
logger.Formatter = new(JSONFormatter)
|
||||
logger.ReportCaller = reportCaller
|
||||
|
||||
for i := 0; i < iterations; i++ {
|
||||
logger.Infof("round %d of %d", i, iterations)
|
||||
}
|
||||
}
|
||||
|
||||
// Assertions for upper bounds to reporting overhead
|
||||
func TestCallerReportingOverhead(t *testing.T) {
|
||||
iterations := 5000
|
||||
before := time.Now()
|
||||
logLoop(iterations, false)
|
||||
during := time.Now()
|
||||
logLoop(iterations, true)
|
||||
after := time.Now()
|
||||
|
||||
elapsedNotReporting := during.Sub(before).Nanoseconds()
|
||||
elapsedReporting := after.Sub(during).Nanoseconds()
|
||||
|
||||
maxDelta := 1 * time.Second
|
||||
assert.WithinDuration(t, during, before, maxDelta,
|
||||
"%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)",
|
||||
iterations, maxDelta.Seconds(), elapsedNotReporting)
|
||||
assert.WithinDuration(t, after, during, maxDelta,
|
||||
"%d log calls without caller name lookup takes less than %d second(s) (was %d nanoseconds)",
|
||||
iterations, maxDelta.Seconds(), elapsedReporting)
|
||||
}
|
||||
|
||||
// benchmarks for both with and without caller-function reporting
|
||||
func BenchmarkWithoutCallerTracing(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
logLoop(1000, false)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWithCallerTracing(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
logLoop(1000, true)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertLevelToString(t *testing.T) {
|
||||
assert.Equal(t, "trace", TraceLevel.String())
|
||||
assert.Equal(t, "debug", DebugLevel.String())
|
||||
assert.Equal(t, "info", InfoLevel.String())
|
||||
assert.Equal(t, "warning", WarnLevel.String())
|
||||
@ -307,6 +509,14 @@ func TestParseLevel(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, DebugLevel, l)
|
||||
|
||||
l, err = ParseLevel("trace")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, TraceLevel, l)
|
||||
|
||||
l, err = ParseLevel("TRACE")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, TraceLevel, l)
|
||||
|
||||
l, err = ParseLevel("invalid")
|
||||
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
|
||||
}
|
||||
@ -343,10 +553,52 @@ func TestLoggingRace(t *testing.T) {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestLoggingRaceWithHooksOnEntry(t *testing.T) {
|
||||
logger := New()
|
||||
hook := new(ModifyHook)
|
||||
logger.AddHook(hook)
|
||||
entry := logger.WithField("context", "clue")
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(100)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
go func() {
|
||||
entry.Info("info")
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestReplaceHooks(t *testing.T) {
|
||||
old, cur := &TestHook{}, &TestHook{}
|
||||
|
||||
logger := New()
|
||||
logger.SetOutput(ioutil.Discard)
|
||||
logger.AddHook(old)
|
||||
|
||||
hooks := make(LevelHooks)
|
||||
hooks.Add(cur)
|
||||
replaced := logger.ReplaceHooks(hooks)
|
||||
|
||||
logger.Info("test")
|
||||
|
||||
assert.Equal(t, old.Fired, false)
|
||||
assert.Equal(t, cur.Fired, true)
|
||||
|
||||
logger.ReplaceHooks(replaced)
|
||||
logger.Info("test")
|
||||
assert.Equal(t, old.Fired, true)
|
||||
}
|
||||
|
||||
// Compile test
|
||||
func TestLogrusInterface(t *testing.T) {
|
||||
func TestLogrusInterfaces(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
fn := func(l FieldLogger) {
|
||||
// This verifies FieldLogger and Ext1FieldLogger work as designed.
|
||||
// Please don't use them. Use Logger and Entry directly.
|
||||
fn := func(xl Ext1FieldLogger) {
|
||||
var l FieldLogger = xl
|
||||
b := l.WithField("key", "value")
|
||||
b.Debug("Test")
|
||||
}
|
||||
@ -384,3 +636,81 @@ func TestEntryWriter(t *testing.T) {
|
||||
assert.Equal(t, fields["foo"], "bar")
|
||||
assert.Equal(t, fields["level"], "warning")
|
||||
}
|
||||
|
||||
func TestLogLevelEnabled(t *testing.T) {
|
||||
log := New()
|
||||
log.SetLevel(PanicLevel)
|
||||
assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(FatalLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(WarnLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
|
||||
|
||||
log.SetLevel(FatalLevel)
|
||||
assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(ErrorLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(WarnLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
|
||||
|
||||
log.SetLevel(ErrorLevel)
|
||||
assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(WarnLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
|
||||
|
||||
log.SetLevel(WarnLevel)
|
||||
assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(InfoLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
|
||||
|
||||
log.SetLevel(InfoLevel)
|
||||
assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(InfoLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(DebugLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
|
||||
|
||||
log.SetLevel(DebugLevel)
|
||||
assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(InfoLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(DebugLevel))
|
||||
assert.Equal(t, false, log.IsLevelEnabled(TraceLevel))
|
||||
|
||||
log.SetLevel(TraceLevel)
|
||||
assert.Equal(t, true, log.IsLevelEnabled(PanicLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(FatalLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(ErrorLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(WarnLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(InfoLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(DebugLevel))
|
||||
assert.Equal(t, true, log.IsLevelEnabled(TraceLevel))
|
||||
}
|
||||
|
||||
func TestReportCallerOnTextFormatter(t *testing.T) {
|
||||
l := New()
|
||||
|
||||
l.Formatter.(*TextFormatter).ForceColors = true
|
||||
l.Formatter.(*TextFormatter).DisableColors = false
|
||||
l.WithFields(Fields{"func": "func", "file": "file"}).Info("test")
|
||||
|
||||
l.Formatter.(*TextFormatter).ForceColors = false
|
||||
l.Formatter.(*TextFormatter).DisableColors = true
|
||||
l.WithFields(Fields{"func": "func", "file": "file"}).Info("test")
|
||||
}
|
||||
|
10
vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
10
vendor/github.com/sirupsen/logrus/terminal_bsd.go
generated
vendored
@ -1,10 +0,0 @@
|
||||
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
// +build !appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TIOCGETA
|
||||
|
||||
type Termios unix.Termios
|
2
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
// +build !appengine
|
||||
// +build !appengine,!js,!windows,!aix
|
||||
|
||||
package logrus
|
||||
|
||||
|
14
vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
14
vendor/github.com/sirupsen/logrus/terminal_linux.go
generated
vendored
@ -1,14 +0,0 @@
|
||||
// Based on ssh/terminal:
|
||||
// Copyright 2013 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 !appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
|
||||
type Termios unix.Termios
|
153
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
153
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
@ -3,6 +3,8 @@ package logrus
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -20,6 +22,7 @@ const (
|
||||
|
||||
var (
|
||||
baseTimestamp time.Time
|
||||
emptyFieldMap FieldMap
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -34,6 +37,9 @@ type TextFormatter struct {
|
||||
// Force disabling colors.
|
||||
DisableColors bool
|
||||
|
||||
// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
|
||||
EnvironmentOverrideColors bool
|
||||
|
||||
// Disable timestamp logging. useful when output is redirected to logging
|
||||
// system that already adds timestamps.
|
||||
DisableTimestamp bool
|
||||
@ -50,60 +56,135 @@ type TextFormatter struct {
|
||||
// be desired.
|
||||
DisableSorting bool
|
||||
|
||||
// The keys sorting function, when uninitialized it uses sort.Strings.
|
||||
SortingFunc func([]string)
|
||||
|
||||
// Disables the truncation of the level text to 4 characters.
|
||||
DisableLevelTruncation bool
|
||||
|
||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||
QuoteEmptyFields bool
|
||||
|
||||
// Whether the logger's out is to a terminal
|
||||
isTerminal bool
|
||||
|
||||
sync.Once
|
||||
// FieldMap allows users to customize the names of keys for default fields.
|
||||
// As an example:
|
||||
// formatter := &TextFormatter{
|
||||
// FieldMap: FieldMap{
|
||||
// FieldKeyTime: "@timestamp",
|
||||
// FieldKeyLevel: "@level",
|
||||
// FieldKeyMsg: "@message"}}
|
||||
FieldMap FieldMap
|
||||
|
||||
terminalInitOnce sync.Once
|
||||
}
|
||||
|
||||
func (f *TextFormatter) init(entry *Entry) {
|
||||
if entry.Logger != nil {
|
||||
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
||||
|
||||
if f.isTerminal {
|
||||
initTerminal(entry.Logger.Out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *TextFormatter) isColored() bool {
|
||||
isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows"))
|
||||
|
||||
if f.EnvironmentOverrideColors {
|
||||
if force, ok := os.LookupEnv("CLICOLOR_FORCE"); ok && force != "0" {
|
||||
isColored = true
|
||||
} else if ok && force == "0" {
|
||||
isColored = false
|
||||
} else if os.Getenv("CLICOLOR") == "0" {
|
||||
isColored = false
|
||||
}
|
||||
}
|
||||
|
||||
return isColored && !f.DisableColors
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
var b *bytes.Buffer
|
||||
keys := make([]string, 0, len(entry.Data))
|
||||
for k := range entry.Data {
|
||||
data := make(Fields)
|
||||
for k, v := range entry.Data {
|
||||
data[k] = v
|
||||
}
|
||||
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
||||
keys := make([]string, 0, len(data))
|
||||
for k := range data {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if !f.DisableSorting {
|
||||
sort.Strings(keys)
|
||||
fixedKeys := make([]string, 0, 4+len(data))
|
||||
if !f.DisableTimestamp {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
||||
}
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel))
|
||||
if entry.Message != "" {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
|
||||
}
|
||||
if entry.err != "" {
|
||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
||||
}
|
||||
if entry.HasCaller() {
|
||||
fixedKeys = append(fixedKeys,
|
||||
f.FieldMap.resolve(FieldKeyFunc), f.FieldMap.resolve(FieldKeyFile))
|
||||
}
|
||||
|
||||
if !f.DisableSorting {
|
||||
if f.SortingFunc == nil {
|
||||
sort.Strings(keys)
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
} else {
|
||||
if !f.isColored() {
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
f.SortingFunc(fixedKeys)
|
||||
} else {
|
||||
f.SortingFunc(keys)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fixedKeys = append(fixedKeys, keys...)
|
||||
}
|
||||
|
||||
var b *bytes.Buffer
|
||||
if entry.Buffer != nil {
|
||||
b = entry.Buffer
|
||||
} else {
|
||||
b = &bytes.Buffer{}
|
||||
}
|
||||
|
||||
prefixFieldClashes(entry.Data)
|
||||
|
||||
f.Do(func() { f.init(entry) })
|
||||
|
||||
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
|
||||
f.terminalInitOnce.Do(func() { f.init(entry) })
|
||||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
if isColored {
|
||||
f.printColored(b, entry, keys, timestampFormat)
|
||||
if f.isColored() {
|
||||
f.printColored(b, entry, keys, data, timestampFormat)
|
||||
} else {
|
||||
if !f.DisableTimestamp {
|
||||
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||
}
|
||||
f.appendKeyValue(b, "level", entry.Level.String())
|
||||
if entry.Message != "" {
|
||||
f.appendKeyValue(b, "msg", entry.Message)
|
||||
}
|
||||
for _, key := range keys {
|
||||
f.appendKeyValue(b, key, entry.Data[key])
|
||||
for _, key := range fixedKeys {
|
||||
var value interface{}
|
||||
switch {
|
||||
case key == f.FieldMap.resolve(FieldKeyTime):
|
||||
value = entry.Time.Format(timestampFormat)
|
||||
case key == f.FieldMap.resolve(FieldKeyLevel):
|
||||
value = entry.Level.String()
|
||||
case key == f.FieldMap.resolve(FieldKeyMsg):
|
||||
value = entry.Message
|
||||
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
||||
value = entry.err
|
||||
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
||||
value = entry.Caller.Function
|
||||
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
||||
value = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
||||
default:
|
||||
value = data[key]
|
||||
}
|
||||
f.appendKeyValue(b, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,10 +192,10 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
return b.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) {
|
||||
var levelColor int
|
||||
switch entry.Level {
|
||||
case DebugLevel:
|
||||
case DebugLevel, TraceLevel:
|
||||
levelColor = gray
|
||||
case WarnLevel:
|
||||
levelColor = yellow
|
||||
@ -124,17 +205,31 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
|
||||
levelColor = blue
|
||||
}
|
||||
|
||||
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||
levelText := strings.ToUpper(entry.Level.String())
|
||||
if !f.DisableLevelTruncation {
|
||||
levelText = levelText[0:4]
|
||||
}
|
||||
|
||||
// Remove a single newline if it already exists in the message to keep
|
||||
// the behavior of logrus text_formatter the same as the stdlib log package
|
||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
||||
|
||||
caller := ""
|
||||
|
||||
if entry.HasCaller() {
|
||||
caller = fmt.Sprintf("%s:%d %s()",
|
||||
entry.Caller.File, entry.Caller.Line, entry.Caller.Function)
|
||||
}
|
||||
|
||||
if f.DisableTimestamp {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
|
||||
} else if !f.FullTimestamp {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message)
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message)
|
||||
} else {
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message)
|
||||
}
|
||||
for _, k := range keys {
|
||||
v := entry.Data[k]
|
||||
v := data[k]
|
||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
|
||||
f.appendValue(b, v)
|
||||
}
|
||||
|
348
vendor/github.com/sirupsen/logrus/text_formatter_test.go
generated
vendored
348
vendor/github.com/sirupsen/logrus/text_formatter_test.go
generated
vendored
@ -4,9 +4,15 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFormatting(t *testing.T) {
|
||||
@ -128,6 +134,44 @@ func TestTimestampFormat(t *testing.T) {
|
||||
checkTimeStr("")
|
||||
}
|
||||
|
||||
func TestDisableLevelTruncation(t *testing.T) {
|
||||
entry := &Entry{
|
||||
Time: time.Now(),
|
||||
Message: "testing",
|
||||
}
|
||||
keys := []string{}
|
||||
timestampFormat := "Mon Jan 2 15:04:05 -0700 MST 2006"
|
||||
checkDisableTruncation := func(disabled bool, level Level) {
|
||||
tf := &TextFormatter{DisableLevelTruncation: disabled}
|
||||
var b bytes.Buffer
|
||||
entry.Level = level
|
||||
tf.printColored(&b, entry, keys, nil, timestampFormat)
|
||||
logLine := (&b).String()
|
||||
if disabled {
|
||||
expected := strings.ToUpper(level.String())
|
||||
if !strings.Contains(logLine, expected) {
|
||||
t.Errorf("level string expected to be %s when truncation disabled", expected)
|
||||
}
|
||||
} else {
|
||||
expected := strings.ToUpper(level.String())
|
||||
if len(level.String()) > 4 {
|
||||
if strings.Contains(logLine, expected) {
|
||||
t.Errorf("level string %s expected to be truncated to %s when truncation is enabled", expected, expected[0:4])
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(logLine, expected) {
|
||||
t.Errorf("level string expected to be %s when truncation is enabled and level string is below truncation threshold", expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkDisableTruncation(true, DebugLevel)
|
||||
checkDisableTruncation(true, InfoLevel)
|
||||
checkDisableTruncation(false, ErrorLevel)
|
||||
checkDisableTruncation(false, InfoLevel)
|
||||
}
|
||||
|
||||
func TestDisableTimestampWithColoredOutput(t *testing.T) {
|
||||
tf := &TextFormatter{DisableTimestamp: true, ForceColors: true}
|
||||
|
||||
@ -137,5 +181,305 @@ func TestDisableTimestampWithColoredOutput(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add tests for sorting etc., this requires a parser for the text
|
||||
// formatter output.
|
||||
func TestNewlineBehavior(t *testing.T) {
|
||||
tf := &TextFormatter{ForceColors: true}
|
||||
|
||||
// Ensure a single new line is removed as per stdlib log
|
||||
e := NewEntry(StandardLogger())
|
||||
e.Message = "test message\n"
|
||||
b, _ := tf.Format(e)
|
||||
if bytes.Contains(b, []byte("test message\n")) {
|
||||
t.Error("first newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected newline to be removed.")
|
||||
}
|
||||
|
||||
// Ensure a double new line is reduced to a single new line
|
||||
e = NewEntry(StandardLogger())
|
||||
e.Message = "test message\n\n"
|
||||
b, _ = tf.Format(e)
|
||||
if bytes.Contains(b, []byte("test message\n\n")) {
|
||||
t.Error("Double newline at end of Entry.Message resulted in unexpected 2 newlines in output. Expected single newline")
|
||||
}
|
||||
if !bytes.Contains(b, []byte("test message\n")) {
|
||||
t.Error("Double newline at end of Entry.Message did not result in a single newline after formatting")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTextFormatterFieldMap(t *testing.T) {
|
||||
formatter := &TextFormatter{
|
||||
DisableColors: true,
|
||||
FieldMap: FieldMap{
|
||||
FieldKeyMsg: "message",
|
||||
FieldKeyLevel: "somelevel",
|
||||
FieldKeyTime: "timeywimey",
|
||||
},
|
||||
}
|
||||
|
||||
entry := &Entry{
|
||||
Message: "oh hi",
|
||||
Level: WarnLevel,
|
||||
Time: time.Date(1981, time.February, 24, 4, 28, 3, 100, time.UTC),
|
||||
Data: Fields{
|
||||
"field1": "f1",
|
||||
"message": "messagefield",
|
||||
"somelevel": "levelfield",
|
||||
"timeywimey": "timeywimeyfield",
|
||||
},
|
||||
}
|
||||
|
||||
b, err := formatter.Format(entry)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to format entry: ", err)
|
||||
}
|
||||
|
||||
assert.Equal(t,
|
||||
`timeywimey="1981-02-24T04:28:03Z" `+
|
||||
`somelevel=warning `+
|
||||
`message="oh hi" `+
|
||||
`field1=f1 `+
|
||||
`fields.message=messagefield `+
|
||||
`fields.somelevel=levelfield `+
|
||||
`fields.timeywimey=timeywimeyfield`+"\n",
|
||||
string(b),
|
||||
"Formatted output doesn't respect FieldMap")
|
||||
}
|
||||
|
||||
func TestTextFormatterIsColored(t *testing.T) {
|
||||
params := []struct {
|
||||
name string
|
||||
expectedResult bool
|
||||
isTerminal bool
|
||||
disableColor bool
|
||||
forceColor bool
|
||||
envColor bool
|
||||
clicolorIsSet bool
|
||||
clicolorForceIsSet bool
|
||||
clicolorVal string
|
||||
clicolorForceVal string
|
||||
}{
|
||||
// Default values
|
||||
{
|
||||
name: "testcase1",
|
||||
expectedResult: false,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: false,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: false,
|
||||
},
|
||||
// Output on terminal
|
||||
{
|
||||
name: "testcase2",
|
||||
expectedResult: true,
|
||||
isTerminal: true,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: false,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: false,
|
||||
},
|
||||
// Output on terminal with color disabled
|
||||
{
|
||||
name: "testcase3",
|
||||
expectedResult: false,
|
||||
isTerminal: true,
|
||||
disableColor: true,
|
||||
forceColor: false,
|
||||
envColor: false,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: false,
|
||||
},
|
||||
// Output not on terminal with color disabled
|
||||
{
|
||||
name: "testcase4",
|
||||
expectedResult: false,
|
||||
isTerminal: false,
|
||||
disableColor: true,
|
||||
forceColor: false,
|
||||
envColor: false,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: false,
|
||||
},
|
||||
// Output not on terminal with color forced
|
||||
{
|
||||
name: "testcase5",
|
||||
expectedResult: true,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: true,
|
||||
envColor: false,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: false,
|
||||
},
|
||||
// Output on terminal with clicolor set to "0"
|
||||
{
|
||||
name: "testcase6",
|
||||
expectedResult: false,
|
||||
isTerminal: true,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: true,
|
||||
clicolorIsSet: true,
|
||||
clicolorForceIsSet: false,
|
||||
clicolorVal: "0",
|
||||
},
|
||||
// Output on terminal with clicolor set to "1"
|
||||
{
|
||||
name: "testcase7",
|
||||
expectedResult: true,
|
||||
isTerminal: true,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: true,
|
||||
clicolorIsSet: true,
|
||||
clicolorForceIsSet: false,
|
||||
clicolorVal: "1",
|
||||
},
|
||||
// Output not on terminal with clicolor set to "0"
|
||||
{
|
||||
name: "testcase8",
|
||||
expectedResult: false,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: true,
|
||||
clicolorIsSet: true,
|
||||
clicolorForceIsSet: false,
|
||||
clicolorVal: "0",
|
||||
},
|
||||
// Output not on terminal with clicolor set to "1"
|
||||
{
|
||||
name: "testcase9",
|
||||
expectedResult: false,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: true,
|
||||
clicolorIsSet: true,
|
||||
clicolorForceIsSet: false,
|
||||
clicolorVal: "1",
|
||||
},
|
||||
// Output not on terminal with clicolor set to "1" and force color
|
||||
{
|
||||
name: "testcase10",
|
||||
expectedResult: true,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: true,
|
||||
envColor: true,
|
||||
clicolorIsSet: true,
|
||||
clicolorForceIsSet: false,
|
||||
clicolorVal: "1",
|
||||
},
|
||||
// Output not on terminal with clicolor set to "0" and force color
|
||||
{
|
||||
name: "testcase11",
|
||||
expectedResult: false,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: true,
|
||||
envColor: true,
|
||||
clicolorIsSet: true,
|
||||
clicolorForceIsSet: false,
|
||||
clicolorVal: "0",
|
||||
},
|
||||
// Output not on terminal with clicolor_force set to "1"
|
||||
{
|
||||
name: "testcase12",
|
||||
expectedResult: true,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: true,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: true,
|
||||
clicolorForceVal: "1",
|
||||
},
|
||||
// Output not on terminal with clicolor_force set to "0"
|
||||
{
|
||||
name: "testcase13",
|
||||
expectedResult: false,
|
||||
isTerminal: false,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: true,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: true,
|
||||
clicolorForceVal: "0",
|
||||
},
|
||||
// Output on terminal with clicolor_force set to "0"
|
||||
{
|
||||
name: "testcase14",
|
||||
expectedResult: false,
|
||||
isTerminal: true,
|
||||
disableColor: false,
|
||||
forceColor: false,
|
||||
envColor: true,
|
||||
clicolorIsSet: false,
|
||||
clicolorForceIsSet: true,
|
||||
clicolorForceVal: "0",
|
||||
},
|
||||
}
|
||||
|
||||
cleanenv := func() {
|
||||
os.Unsetenv("CLICOLOR")
|
||||
os.Unsetenv("CLICOLOR_FORCE")
|
||||
}
|
||||
|
||||
defer cleanenv()
|
||||
|
||||
for _, val := range params {
|
||||
t.Run("textformatter_"+val.name, func(subT *testing.T) {
|
||||
tf := TextFormatter{
|
||||
isTerminal: val.isTerminal,
|
||||
DisableColors: val.disableColor,
|
||||
ForceColors: val.forceColor,
|
||||
EnvironmentOverrideColors: val.envColor,
|
||||
}
|
||||
cleanenv()
|
||||
if val.clicolorIsSet {
|
||||
os.Setenv("CLICOLOR", val.clicolorVal)
|
||||
}
|
||||
if val.clicolorForceIsSet {
|
||||
os.Setenv("CLICOLOR_FORCE", val.clicolorForceVal)
|
||||
}
|
||||
res := tf.isColored()
|
||||
if runtime.GOOS == "windows" && !tf.ForceColors && !val.clicolorForceIsSet {
|
||||
assert.Equal(subT, false, res)
|
||||
} else {
|
||||
assert.Equal(subT, val.expectedResult, res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomSorting(t *testing.T) {
|
||||
formatter := &TextFormatter{
|
||||
DisableColors: true,
|
||||
SortingFunc: func(keys []string) {
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
if keys[j] == "prefix" {
|
||||
return false
|
||||
}
|
||||
if keys[i] == "prefix" {
|
||||
return true
|
||||
}
|
||||
return strings.Compare(keys[i], keys[j]) == -1
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
entry := &Entry{
|
||||
Message: "Testing custom sort function",
|
||||
Time: time.Now(),
|
||||
Level: InfoLevel,
|
||||
Data: Fields{
|
||||
"test": "testvalue",
|
||||
"prefix": "the application prefix",
|
||||
"blablabla": "blablabla",
|
||||
},
|
||||
}
|
||||
b, err := formatter.Format(entry)
|
||||
require.NoError(t, err)
|
||||
require.True(t, strings.HasPrefix(string(b), "prefix="), "format output is %q", string(b))
|
||||
}
|
||||
|
2
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
2
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
@ -24,6 +24,8 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
||||
var printFunc func(args ...interface{})
|
||||
|
||||
switch level {
|
||||
case TraceLevel:
|
||||
printFunc = entry.Trace
|
||||
case DebugLevel:
|
||||
printFunc = entry.Debug
|
||||
case InfoLevel:
|
||||
|
15
vendor/golang.org/x/crypto/CONTRIBUTING.md
generated
vendored
15
vendor/golang.org/x/crypto/CONTRIBUTING.md
generated
vendored
@ -4,16 +4,15 @@ Go is an open source project.
|
||||
|
||||
It is the work of hundreds of contributors. We appreciate your help!
|
||||
|
||||
|
||||
## Filing issues
|
||||
|
||||
When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
|
||||
|
||||
1. What version of Go are you using (`go version`)?
|
||||
2. What operating system and processor architecture are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
1. What version of Go are you using (`go version`)?
|
||||
2. What operating system and processor architecture are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
|
||||
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||
@ -23,9 +22,5 @@ The gophers there will answer or ask you to file an issue if you've tripped over
|
||||
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
|
||||
before sending patches.
|
||||
|
||||
**We do not accept GitHub pull requests**
|
||||
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed under
|
||||
the BSD-style license found in the LICENSE file.
|
||||
|
||||
|
475
vendor/golang.org/x/crypto/acme/acme.go
generated
vendored
475
vendor/golang.org/x/crypto/acme/acme.go
generated
vendored
@ -14,7 +14,6 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
@ -23,6 +22,8 @@ import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
@ -33,14 +34,26 @@ import (
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
|
||||
const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
|
||||
const (
|
||||
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
|
||||
LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
|
||||
|
||||
// ALPNProto is the ALPN protocol name used by a CA server when validating
|
||||
// tls-alpn-01 challenges.
|
||||
//
|
||||
// Package users must ensure their servers can negotiate the ACME ALPN in
|
||||
// order for tls-alpn-01 challenge verifications to succeed.
|
||||
// See the crypto/tls package's Config.NextProtos field.
|
||||
ALPNProto = "acme-tls/1"
|
||||
)
|
||||
|
||||
// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge.
|
||||
var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1}
|
||||
|
||||
const (
|
||||
maxChainLen = 5 // max depth and breadth of a certificate chain
|
||||
@ -64,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
|
||||
@ -76,6 +93,22 @@ type Client struct {
|
||||
// will have no effect.
|
||||
DirectoryURL string
|
||||
|
||||
// RetryBackoff computes the duration after which the nth retry of a failed request
|
||||
// should occur. The value of n for the first call on failure is 1.
|
||||
// The values of r and resp are the request and response of the last failed attempt.
|
||||
// If the returned value is negative or zero, no more retries are done and an error
|
||||
// is returned to the caller of the original method.
|
||||
//
|
||||
// Requests which result in a 4xx client error are not retried,
|
||||
// except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests.
|
||||
//
|
||||
// If RetryBackoff is nil, a truncated exponential backoff algorithm
|
||||
// with the ceiling of 10 seconds is used, where each subsequent retry n
|
||||
// is done after either ("Retry-After" + jitter) or (2^n seconds + jitter),
|
||||
// preferring the former if "Retry-After" header is found in the resp.
|
||||
// The jitter is a random value up to 1 second.
|
||||
RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration
|
||||
|
||||
dirMu sync.Mutex // guards writes to dir
|
||||
dir *Directory // cached result of Client's Discover method
|
||||
|
||||
@ -95,19 +128,12 @@ 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)
|
||||
res, err := c.get(ctx, c.directoryURL(), wantStatus(http.StatusOK))
|
||||
if err != nil {
|
||||
return Directory{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
c.addNonce(res.Header)
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return Directory{}, responseError(res)
|
||||
}
|
||||
|
||||
var v struct {
|
||||
Reg string `json:"new-reg"`
|
||||
@ -135,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.
|
||||
@ -166,14 +199,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
||||
req.NotAfter = now.Add(exp).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req)
|
||||
res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return nil, "", responseError(res)
|
||||
}
|
||||
|
||||
curl := res.Header.Get("Location") // cert permanent URL
|
||||
if res.ContentLength == 0 {
|
||||
@ -196,26 +226,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
||||
// Callers are encouraged to parse the returned value to ensure the certificate is valid
|
||||
// and has expected features.
|
||||
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
|
||||
for {
|
||||
res, err := c.get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusOK {
|
||||
return c.responseCert(ctx, res, bundle)
|
||||
}
|
||||
if res.StatusCode > 299 {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second)
|
||||
select {
|
||||
case <-time.After(d):
|
||||
// retry
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
res, err := c.get(ctx, url, wantStatus(http.StatusOK))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.responseCert(ctx, res, bundle)
|
||||
}
|
||||
|
||||
// RevokeCert revokes a previously issued certificate cert, provided in DER format.
|
||||
@ -241,14 +256,11 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
|
||||
if key == nil {
|
||||
key = c.Key
|
||||
}
|
||||
res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body)
|
||||
res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return responseError(res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -314,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
|
||||
}
|
||||
@ -327,16 +353,13 @@ 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.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req)
|
||||
res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
|
||||
var v wireAuthz
|
||||
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||
@ -353,14 +376,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
|
||||
// If a caller needs to poll an authorization until its status is final,
|
||||
// see the WaitAuthorization method.
|
||||
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
||||
res, err := c.get(ctx, url)
|
||||
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
var v wireAuthz
|
||||
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||
return nil, fmt.Errorf("acme: invalid response: %v", err)
|
||||
@ -387,56 +407,58 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
|
||||
Status: "deactivated",
|
||||
Delete: true,
|
||||
}
|
||||
res, err := c.retryPostJWS(ctx, c.Key, url, req)
|
||||
res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return responseError(res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitAuthorization polls an authorization at the given URL
|
||||
// until it is in one of the final states, StatusValid or StatusInvalid,
|
||||
// or the context is done.
|
||||
// the ACME CA responded with a 4xx error code, or the context is done.
|
||||
//
|
||||
// It returns a non-nil Authorization only if its Status is StatusValid.
|
||||
// In all other cases WaitAuthorization returns an error.
|
||||
// If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
|
||||
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
||||
sleep := sleeper(ctx)
|
||||
for {
|
||||
res, err := c.get(ctx, url)
|
||||
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retry := res.Header.Get("Retry-After")
|
||||
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
|
||||
res.Body.Close()
|
||||
if err := sleep(retry, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var raw wireAuthz
|
||||
err = json.NewDecoder(res.Body).Decode(&raw)
|
||||
res.Body.Close()
|
||||
if err != nil {
|
||||
if err := sleep(retry, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
if raw.Status == StatusValid {
|
||||
switch {
|
||||
case err != nil:
|
||||
// Skip and retry.
|
||||
case raw.Status == StatusValid:
|
||||
return raw.authorization(url), nil
|
||||
}
|
||||
if raw.Status == StatusInvalid {
|
||||
case raw.Status == StatusInvalid:
|
||||
return nil, raw.error(url)
|
||||
}
|
||||
if err := sleep(retry, 0); err != nil {
|
||||
return nil, err
|
||||
|
||||
// Exponential backoff is implemented in c.get above.
|
||||
// This is just to prevent continuously hitting the CA
|
||||
// while waiting for a final authorization status.
|
||||
d := retryAfter(res.Header.Get("Retry-After"))
|
||||
if d == 0 {
|
||||
// Given that the fastest challenges TLS-SNI and HTTP-01
|
||||
// require a CA to make at least 1 network round trip
|
||||
// and most likely persist a challenge state,
|
||||
// this default delay seems reasonable.
|
||||
d = time.Second
|
||||
}
|
||||
t := time.NewTimer(d)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Stop()
|
||||
return nil, ctx.Err()
|
||||
case <-t.C:
|
||||
// Retry.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,14 +467,11 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
|
||||
//
|
||||
// A client typically polls a challenge status using this method.
|
||||
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
|
||||
res, err := c.get(ctx, url)
|
||||
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
v := wireChallenge{URI: url}
|
||||
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||
return nil, fmt.Errorf("acme: invalid response: %v", err)
|
||||
@ -479,16 +498,14 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error
|
||||
Type: chal.Type,
|
||||
Auth: auth,
|
||||
}
|
||||
res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req)
|
||||
res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus(
|
||||
http.StatusOK, // according to the spec
|
||||
http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
// Note: the protocol specifies 200 as the expected response code, but
|
||||
// letsencrypt seems to be returning 202.
|
||||
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
|
||||
var v wireChallenge
|
||||
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||
@ -545,7 +562,7 @@ func (c *Client) HTTP01ChallengePath(token string) string {
|
||||
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
|
||||
//
|
||||
// The returned certificate is valid for the next 24 hours and must be presented only when
|
||||
// the server name of the client hello matches exactly the returned name value.
|
||||
// the server name of the TLS ClientHello matches exactly the returned name value.
|
||||
func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
|
||||
ka, err := keyAuth(c.Key.Public(), token)
|
||||
if err != nil {
|
||||
@ -572,7 +589,7 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl
|
||||
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
|
||||
//
|
||||
// The returned certificate is valid for the next 24 hours and must be presented only when
|
||||
// the server name in the client hello matches exactly the returned name value.
|
||||
// the server name in the TLS ClientHello matches exactly the returned name value.
|
||||
func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) {
|
||||
b := sha256.Sum256([]byte(token))
|
||||
h := hex.EncodeToString(b[:])
|
||||
@ -593,6 +610,52 @@ func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tl
|
||||
return cert, sanA, nil
|
||||
}
|
||||
|
||||
// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response.
|
||||
// Servers can present the certificate to validate the challenge and prove control
|
||||
// over a domain name. For more details on TLS-ALPN-01 see
|
||||
// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3
|
||||
//
|
||||
// The token argument is a Challenge.Token value.
|
||||
// If a WithKey option is provided, its private part signs the returned cert,
|
||||
// and the public part is used to specify the signee.
|
||||
// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
|
||||
//
|
||||
// The returned certificate is valid for the next 24 hours and must be presented only when
|
||||
// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol
|
||||
// has been specified.
|
||||
func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) {
|
||||
ka, err := keyAuth(c.Key.Public(), token)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
shasum := sha256.Sum256([]byte(ka))
|
||||
extValue, err := asn1.Marshal(shasum[:])
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
acmeExtension := pkix.Extension{
|
||||
Id: idPeACMEIdentifierV1,
|
||||
Critical: true,
|
||||
Value: extValue,
|
||||
}
|
||||
|
||||
tmpl := defaultTLSChallengeCertTemplate()
|
||||
|
||||
var newOpt []CertOption
|
||||
for _, o := range opt {
|
||||
switch o := o.(type) {
|
||||
case *certOptTemplate:
|
||||
t := *(*x509.Certificate)(o) // shallow copy is ok
|
||||
tmpl = &t
|
||||
default:
|
||||
newOpt = append(newOpt, o)
|
||||
}
|
||||
}
|
||||
tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension)
|
||||
newOpt = append(newOpt, WithTemplate(tmpl))
|
||||
return tlsChallengeCert([]string{domain}, newOpt)
|
||||
}
|
||||
|
||||
// doReg sends all types of registration requests.
|
||||
// The type of request is identified by typ argument, which is a "resource"
|
||||
// in the ACME spec terms.
|
||||
@ -612,14 +675,15 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
||||
req.Contact = acct.Contact
|
||||
req.Agreement = acct.AgreedTerms
|
||||
}
|
||||
res, err := c.retryPostJWS(ctx, c.Key, url, req)
|
||||
res, err := c.post(ctx, c.Key, url, req, wantStatus(
|
||||
http.StatusOK, // updates and deletes
|
||||
http.StatusCreated, // new account creation
|
||||
http.StatusAccepted, // Let's Encrypt divergent implementation
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
|
||||
var v struct {
|
||||
Contact []string
|
||||
@ -649,66 +713,19 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
||||
}, nil
|
||||
}
|
||||
|
||||
// retryPostJWS will retry calls to postJWS if there is a badNonce error,
|
||||
// clearing the stored nonces after each error.
|
||||
// If the response was 4XX-5XX, then responseError is called on the body,
|
||||
// the body is closed, and the error returned.
|
||||
func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
||||
sleep := sleeper(ctx)
|
||||
for {
|
||||
res, err := c.postJWS(ctx, key, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// handle errors 4XX-5XX with responseError
|
||||
if res.StatusCode >= 400 && res.StatusCode <= 599 {
|
||||
err := responseError(res)
|
||||
res.Body.Close()
|
||||
// according to spec badNonce is urn:ietf:params:acme:error:badNonce
|
||||
// however, acme servers in the wild return their version of the error
|
||||
// https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
|
||||
if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") {
|
||||
// clear any nonces that we might've stored that might now be
|
||||
// considered bad
|
||||
c.clearNonces()
|
||||
retry := res.Header.Get("Retry-After")
|
||||
if err := sleep(retry, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
// postJWS signs the body with the given key and POSTs it to the provided url.
|
||||
// The body argument must be JSON-serializable.
|
||||
func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
||||
nonce, err := c.popNonce(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := jwsEncodeJSON(body, key, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.addNonce(res.Header)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@ -742,58 +759,12 @@ func (c *Client) addNonce(h http.Header) {
|
||||
c.nonces[v] = struct{}{}
|
||||
}
|
||||
|
||||
func (c *Client) httpClient() *http.Client {
|
||||
if c.HTTPClient != nil {
|
||||
return c.HTTPClient
|
||||
}
|
||||
return http.DefaultClient
|
||||
}
|
||||
|
||||
func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("GET", urlStr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.do(ctx, req)
|
||||
}
|
||||
|
||||
func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("HEAD", urlStr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.do(ctx, req)
|
||||
}
|
||||
|
||||
func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) {
|
||||
req, err := http.NewRequest("POST", urlStr, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
return c.do(ctx, req)
|
||||
}
|
||||
|
||||
func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
|
||||
res, err := c.httpClient().Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// Prefer the unadorned context error.
|
||||
// (The acme package had tests assuming this, previously from ctxhttp's
|
||||
// behavior, predating net/http supporting contexts natively)
|
||||
// TODO(bradfitz): reconsider this in the future. But for now this
|
||||
// requires no test updates.
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
|
||||
resp, err := c.head(ctx, url)
|
||||
r, err := http.NewRequest("HEAD", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := c.doNoRetry(ctx, r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -845,24 +816,6 @@ func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bo
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// responseError creates an error of Error type from resp.
|
||||
func responseError(resp *http.Response) error {
|
||||
// don't care if ReadAll returns an error:
|
||||
// json.Unmarshal will fail in that case anyway
|
||||
b, _ := ioutil.ReadAll(resp.Body)
|
||||
e := &wireError{Status: resp.StatusCode}
|
||||
if err := json.Unmarshal(b, e); err != nil {
|
||||
// this is not a regular error response:
|
||||
// populate detail with anything we received,
|
||||
// e.Status will already contain HTTP response code value
|
||||
e.Detail = string(b)
|
||||
if e.Detail == "" {
|
||||
e.Detail = resp.Status
|
||||
}
|
||||
}
|
||||
return e.error(resp.Header)
|
||||
}
|
||||
|
||||
// chainCert fetches CA certificate chain recursively by following "up" links.
|
||||
// Each recursive call increments the depth by 1, resulting in an error
|
||||
// if the recursion level reaches maxChainLen.
|
||||
@ -873,14 +826,11 @@ func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte
|
||||
return nil, errors.New("acme: certificate chain is too deep")
|
||||
}
|
||||
|
||||
res, err := c.get(ctx, url)
|
||||
res, err := c.get(ctx, url, wantStatus(http.StatusOK))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -925,65 +875,6 @@ func linkHeader(h http.Header, rel string) []string {
|
||||
return links
|
||||
}
|
||||
|
||||
// sleeper returns a function that accepts the Retry-After HTTP header value
|
||||
// and an increment that's used with backoff to increasingly sleep on
|
||||
// consecutive calls until the context is done. If the Retry-After header
|
||||
// cannot be parsed, then backoff is used with a maximum sleep time of 10
|
||||
// seconds.
|
||||
func sleeper(ctx context.Context) func(ra string, inc int) error {
|
||||
var count int
|
||||
return func(ra string, inc int) error {
|
||||
count += inc
|
||||
d := backoff(count, 10*time.Second)
|
||||
d = retryAfter(ra, d)
|
||||
wakeup := time.NewTimer(d)
|
||||
defer wakeup.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-wakeup.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// retryAfter parses a Retry-After HTTP header value,
|
||||
// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
|
||||
// It returns d if v cannot be parsed.
|
||||
func retryAfter(v string, d time.Duration) time.Duration {
|
||||
if i, err := strconv.Atoi(v); err == nil {
|
||||
return time.Duration(i) * time.Second
|
||||
}
|
||||
t, err := http.ParseTime(v)
|
||||
if err != nil {
|
||||
return d
|
||||
}
|
||||
return t.Sub(timeNow())
|
||||
}
|
||||
|
||||
// backoff computes a duration after which an n+1 retry iteration should occur
|
||||
// using truncated exponential backoff algorithm.
|
||||
//
|
||||
// The n argument is always bounded between 0 and 30.
|
||||
// The max argument defines upper bound for the returned value.
|
||||
func backoff(n int, max time.Duration) time.Duration {
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
if n > 30 {
|
||||
n = 30
|
||||
}
|
||||
var d time.Duration
|
||||
if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil {
|
||||
d = time.Duration(x.Int64()) * time.Millisecond
|
||||
}
|
||||
d += time.Duration(1<<uint(n)) * time.Second
|
||||
if d > max {
|
||||
return max
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// keyAuth generates a key authorization string for a given token.
|
||||
func keyAuth(pub crypto.PublicKey, token string) (string, error) {
|
||||
th, err := JWKThumbprint(pub)
|
||||
@ -993,15 +884,25 @@ func keyAuth(pub crypto.PublicKey, token string) (string, error) {
|
||||
return fmt.Sprintf("%s.%s", token, th), nil
|
||||
}
|
||||
|
||||
// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges.
|
||||
func defaultTLSChallengeCertTemplate() *x509.Certificate {
|
||||
return &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(24 * time.Hour),
|
||||
BasicConstraintsValid: true,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
}
|
||||
}
|
||||
|
||||
// tlsChallengeCert creates a temporary certificate for TLS-SNI challenges
|
||||
// with the given SANs and auto-generated public/private key pair.
|
||||
// The Subject Common Name is set to the first SAN to aid debugging.
|
||||
// To create a cert with a custom key pair, specify WithKey option.
|
||||
func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
||||
var (
|
||||
key crypto.Signer
|
||||
tmpl *x509.Certificate
|
||||
)
|
||||
var key crypto.Signer
|
||||
tmpl := defaultTLSChallengeCertTemplate()
|
||||
for _, o := range opt {
|
||||
switch o := o.(type) {
|
||||
case *certOptKey:
|
||||
@ -1010,7 +911,7 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
||||
}
|
||||
key = o.key
|
||||
case *certOptTemplate:
|
||||
var t = *(*x509.Certificate)(o) // shallow copy is ok
|
||||
t := *(*x509.Certificate)(o) // shallow copy is ok
|
||||
tmpl = &t
|
||||
default:
|
||||
// package's fault, if we let this happen:
|
||||
@ -1023,16 +924,6 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
||||
return tls.Certificate{}, err
|
||||
}
|
||||
}
|
||||
if tmpl == nil {
|
||||
tmpl = &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(24 * time.Hour),
|
||||
BasicConstraintsValid: true,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
}
|
||||
}
|
||||
tmpl.DNSNames = san
|
||||
if len(san) > 0 {
|
||||
tmpl.Subject.CommonName = san[0]
|
||||
|
589
vendor/golang.org/x/crypto/acme/acme_test.go
generated
vendored
589
vendor/golang.org/x/crypto/acme/acme_test.go
generated
vendored
@ -13,9 +13,9 @@ import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -75,6 +75,7 @@ func TestDiscover(t *testing.T) {
|
||||
)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Replay-Nonce", "testnonce")
|
||||
fmt.Fprintf(w, `{
|
||||
"new-reg": %q,
|
||||
"new-authz": %q,
|
||||
@ -100,6 +101,9 @@ func TestDiscover(t *testing.T) {
|
||||
if dir.RevokeURL != revoke {
|
||||
t.Errorf("dir.RevokeURL = %q; want %q", dir.RevokeURL, revoke)
|
||||
}
|
||||
if _, exist := c.nonces["testnonce"]; !exist {
|
||||
t.Errorf("c.nonces = %q; want 'testnonce' in the map", c.nonces)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
@ -147,7 +151,11 @@ func TestRegister(t *testing.T) {
|
||||
return false
|
||||
}
|
||||
|
||||
c := Client{Key: testKeyEC, dir: &Directory{RegURL: ts.URL}}
|
||||
c := Client{
|
||||
Key: testKeyEC,
|
||||
DirectoryURL: ts.URL,
|
||||
dir: &Directory{RegURL: ts.URL},
|
||||
}
|
||||
a := &Account{Contact: contacts}
|
||||
var err error
|
||||
if a, err = c.Register(context.Background(), a, prompt); err != nil {
|
||||
@ -288,106 +296,131 @@ func TestGetReg(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuthorize(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
t.Errorf("r.Method = %q; want POST", r.Method)
|
||||
}
|
||||
|
||||
var j struct {
|
||||
Resource string
|
||||
Identifier struct {
|
||||
Type string
|
||||
Value string
|
||||
}
|
||||
}
|
||||
decodeJWSRequest(t, &j, r)
|
||||
|
||||
// Test request
|
||||
if j.Resource != "new-authz" {
|
||||
t.Errorf("j.Resource = %q; want new-authz", j.Resource)
|
||||
}
|
||||
if j.Identifier.Type != "dns" {
|
||||
t.Errorf("j.Identifier.Type = %q; want dns", j.Identifier.Type)
|
||||
}
|
||||
if j.Identifier.Value != "example.com" {
|
||||
t.Errorf("j.Identifier.Value = %q; want example.com", j.Identifier.Value)
|
||||
}
|
||||
|
||||
w.Header().Set("Location", "https://ca.tld/acme/auth/1")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
fmt.Fprintf(w, `{
|
||||
"identifier": {"type":"dns","value":"example.com"},
|
||||
"status":"pending",
|
||||
"challenges":[
|
||||
{
|
||||
"type":"http-01",
|
||||
"status":"pending",
|
||||
"uri":"https://ca.tld/acme/challenge/publickey/id1",
|
||||
"token":"token1"
|
||||
},
|
||||
{
|
||||
"type":"tls-sni-01",
|
||||
"status":"pending",
|
||||
"uri":"https://ca.tld/acme/challenge/publickey/id2",
|
||||
"token":"token2"
|
||||
tt := []struct{ typ, value string }{
|
||||
{"dns", "example.com"},
|
||||
{"ip", "1.2.3.4"},
|
||||
}
|
||||
for _, test := range tt {
|
||||
t.Run(test.typ, func(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
t.Errorf("r.Method = %q; want POST", r.Method)
|
||||
}
|
||||
],
|
||||
"combinations":[[0],[1]]}`)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
cl := Client{Key: testKeyEC, dir: &Directory{AuthzURL: ts.URL}}
|
||||
auth, err := cl.Authorize(context.Background(), "example.com")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var j struct {
|
||||
Resource string
|
||||
Identifier struct {
|
||||
Type string
|
||||
Value string
|
||||
}
|
||||
}
|
||||
decodeJWSRequest(t, &j, r)
|
||||
|
||||
if auth.URI != "https://ca.tld/acme/auth/1" {
|
||||
t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
|
||||
}
|
||||
if auth.Status != "pending" {
|
||||
t.Errorf("Status = %q; want pending", auth.Status)
|
||||
}
|
||||
if auth.Identifier.Type != "dns" {
|
||||
t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
|
||||
}
|
||||
if auth.Identifier.Value != "example.com" {
|
||||
t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
|
||||
}
|
||||
// Test request
|
||||
if j.Resource != "new-authz" {
|
||||
t.Errorf("j.Resource = %q; want new-authz", j.Resource)
|
||||
}
|
||||
if j.Identifier.Type != test.typ {
|
||||
t.Errorf("j.Identifier.Type = %q; want %q", j.Identifier.Type, test.typ)
|
||||
}
|
||||
if j.Identifier.Value != test.value {
|
||||
t.Errorf("j.Identifier.Value = %q; want %q", j.Identifier.Value, test.value)
|
||||
}
|
||||
|
||||
if n := len(auth.Challenges); n != 2 {
|
||||
t.Fatalf("len(auth.Challenges) = %d; want 2", n)
|
||||
}
|
||||
w.Header().Set("Location", "https://ca.tld/acme/auth/1")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
fmt.Fprintf(w, `{
|
||||
"identifier": {"type":%q,"value":%q},
|
||||
"status":"pending",
|
||||
"challenges":[
|
||||
{
|
||||
"type":"http-01",
|
||||
"status":"pending",
|
||||
"uri":"https://ca.tld/acme/challenge/publickey/id1",
|
||||
"token":"token1"
|
||||
},
|
||||
{
|
||||
"type":"tls-sni-01",
|
||||
"status":"pending",
|
||||
"uri":"https://ca.tld/acme/challenge/publickey/id2",
|
||||
"token":"token2"
|
||||
}
|
||||
],
|
||||
"combinations":[[0],[1]]
|
||||
}`, test.typ, test.value)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
c := auth.Challenges[0]
|
||||
if c.Type != "http-01" {
|
||||
t.Errorf("c.Type = %q; want http-01", c.Type)
|
||||
}
|
||||
if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
|
||||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
|
||||
}
|
||||
if c.Token != "token1" {
|
||||
t.Errorf("c.Token = %q; want token1", c.Token)
|
||||
}
|
||||
var (
|
||||
auth *Authorization
|
||||
err error
|
||||
)
|
||||
cl := Client{
|
||||
Key: testKeyEC,
|
||||
DirectoryURL: ts.URL,
|
||||
dir: &Directory{AuthzURL: ts.URL},
|
||||
}
|
||||
switch test.typ {
|
||||
case "dns":
|
||||
auth, err = cl.Authorize(context.Background(), test.value)
|
||||
case "ip":
|
||||
auth, err = cl.AuthorizeIP(context.Background(), test.value)
|
||||
default:
|
||||
t.Fatalf("unknown identifier type: %q", test.typ)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c = auth.Challenges[1]
|
||||
if c.Type != "tls-sni-01" {
|
||||
t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
|
||||
}
|
||||
if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
|
||||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
|
||||
}
|
||||
if c.Token != "token2" {
|
||||
t.Errorf("c.Token = %q; want token2", c.Token)
|
||||
}
|
||||
if auth.URI != "https://ca.tld/acme/auth/1" {
|
||||
t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
|
||||
}
|
||||
if auth.Status != "pending" {
|
||||
t.Errorf("Status = %q; want pending", auth.Status)
|
||||
}
|
||||
if auth.Identifier.Type != test.typ {
|
||||
t.Errorf("Identifier.Type = %q; want %q", auth.Identifier.Type, test.typ)
|
||||
}
|
||||
if auth.Identifier.Value != test.value {
|
||||
t.Errorf("Identifier.Value = %q; want %q", auth.Identifier.Value, test.value)
|
||||
}
|
||||
|
||||
combs := [][]int{{0}, {1}}
|
||||
if !reflect.DeepEqual(auth.Combinations, combs) {
|
||||
t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
|
||||
if n := len(auth.Challenges); n != 2 {
|
||||
t.Fatalf("len(auth.Challenges) = %d; want 2", n)
|
||||
}
|
||||
|
||||
c := auth.Challenges[0]
|
||||
if c.Type != "http-01" {
|
||||
t.Errorf("c.Type = %q; want http-01", c.Type)
|
||||
}
|
||||
if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
|
||||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
|
||||
}
|
||||
if c.Token != "token1" {
|
||||
t.Errorf("c.Token = %q; want token1", c.Token)
|
||||
}
|
||||
|
||||
c = auth.Challenges[1]
|
||||
if c.Type != "tls-sni-01" {
|
||||
t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
|
||||
}
|
||||
if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
|
||||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
|
||||
}
|
||||
if c.Token != "token2" {
|
||||
t.Errorf("c.Token = %q; want token2", c.Token)
|
||||
}
|
||||
|
||||
combs := [][]int{{0}, {1}}
|
||||
if !reflect.DeepEqual(auth.Combinations, combs) {
|
||||
t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,7 +434,11 @@ func TestAuthorizeValid(t *testing.T) {
|
||||
w.Write([]byte(`{"status":"valid"}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
|
||||
client := Client{
|
||||
Key: testKey,
|
||||
DirectoryURL: ts.URL,
|
||||
dir: &Directory{AuthzURL: ts.URL},
|
||||
}
|
||||
_, err := client.Authorize(context.Background(), "example.com")
|
||||
if err != nil {
|
||||
t.Errorf("err = %v", err)
|
||||
@ -485,95 +522,98 @@ func TestGetAuthorization(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWaitAuthorization(t *testing.T) {
|
||||
var count int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("Retry-After", "0")
|
||||
if count > 1 {
|
||||
fmt.Fprintf(w, `{"status":"valid"}`)
|
||||
return
|
||||
t.Run("wait loop", func(t *testing.T) {
|
||||
var count int
|
||||
authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("Retry-After", "0")
|
||||
if count > 1 {
|
||||
fmt.Fprintf(w, `{"status":"valid"}`)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(w, `{"status":"pending"}`)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("non-nil error: %v", err)
|
||||
}
|
||||
fmt.Fprintf(w, `{"status":"pending"}`)
|
||||
}))
|
||||
if authz == nil {
|
||||
t.Fatal("authz is nil")
|
||||
}
|
||||
})
|
||||
t.Run("invalid status", func(t *testing.T) {
|
||||
_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{"status":"invalid"}`)
|
||||
})
|
||||
if _, ok := err.(*AuthorizationError); !ok {
|
||||
t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err)
|
||||
}
|
||||
})
|
||||
t.Run("non-retriable error", func(t *testing.T) {
|
||||
const code = http.StatusBadRequest
|
||||
_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(code)
|
||||
})
|
||||
res, ok := err.(*Error)
|
||||
if !ok {
|
||||
t.Fatalf("err is %v (%T); want a non-nil *Error", err, err)
|
||||
}
|
||||
if res.StatusCode != code {
|
||||
t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, code)
|
||||
}
|
||||
})
|
||||
for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} {
|
||||
t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) {
|
||||
var count int
|
||||
authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("Retry-After", "0")
|
||||
if count > 1 {
|
||||
fmt.Fprintf(w, `{"status":"valid"}`)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(code)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("non-nil error: %v", err)
|
||||
}
|
||||
if authz == nil {
|
||||
t.Fatal("authz is nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("context cancel", func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
||||
defer cancel()
|
||||
_, err := runWaitAuthorization(ctx, t, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Retry-After", "60")
|
||||
fmt.Fprintf(w, `{"status":"pending"}`)
|
||||
})
|
||||
if err == nil {
|
||||
t.Error("err is nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc) (*Authorization, error) {
|
||||
t.Helper()
|
||||
ts := httptest.NewServer(h)
|
||||
defer ts.Close()
|
||||
|
||||
type res struct {
|
||||
authz *Authorization
|
||||
err error
|
||||
}
|
||||
done := make(chan res)
|
||||
defer close(done)
|
||||
ch := make(chan res, 1)
|
||||
go func() {
|
||||
var client Client
|
||||
a, err := client.WaitAuthorization(context.Background(), ts.URL)
|
||||
done <- res{a, err}
|
||||
a, err := client.WaitAuthorization(ctx, ts.URL)
|
||||
ch <- res{a, err}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("WaitAuthz took too long to return")
|
||||
case res := <-done:
|
||||
if res.err != nil {
|
||||
t.Fatalf("res.err = %v", res.err)
|
||||
}
|
||||
if res.authz == nil {
|
||||
t.Fatal("res.authz is nil")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitAuthorizationInvalid(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, `{"status":"invalid"}`)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
res := make(chan error)
|
||||
defer close(res)
|
||||
go func() {
|
||||
var client Client
|
||||
_, err := client.WaitAuthorization(context.Background(), ts.URL)
|
||||
res <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("WaitAuthz took too long to return")
|
||||
case err := <-res:
|
||||
if err == nil {
|
||||
t.Error("err is nil")
|
||||
}
|
||||
if _, ok := err.(*AuthorizationError); !ok {
|
||||
t.Errorf("err is %T; want *AuthorizationError", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitAuthorizationCancel(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Retry-After", "60")
|
||||
fmt.Fprintf(w, `{"status":"pending"}`)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
res := make(chan error)
|
||||
defer close(res)
|
||||
go func() {
|
||||
var client Client
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
||||
defer cancel()
|
||||
_, err := client.WaitAuthorization(ctx, ts.URL)
|
||||
res <- err
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("WaitAuthz took too long to return")
|
||||
case err := <-res:
|
||||
if err == nil {
|
||||
t.Error("err is nil")
|
||||
}
|
||||
t.Fatal("WaitAuthorization took too long to return")
|
||||
case v := <-ch:
|
||||
return v.authz, v.err
|
||||
}
|
||||
panic("runWaitAuthorization: out of select")
|
||||
}
|
||||
|
||||
func TestRevokeAuthorization(t *testing.T) {
|
||||
@ -600,7 +640,7 @@ func TestRevokeAuthorization(t *testing.T) {
|
||||
t.Errorf("req.Delete is false")
|
||||
}
|
||||
case "/2":
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
@ -821,7 +861,7 @@ func TestFetchCertRetry(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if count < 1 {
|
||||
w.Header().Set("Retry-After", "0")
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
w.WriteHeader(http.StatusTooManyRequests)
|
||||
count++
|
||||
return
|
||||
}
|
||||
@ -1013,6 +1053,53 @@ func TestNonce_fetchError(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_popWhenEmpty(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "HEAD" {
|
||||
t.Errorf("r.Method = %q; want HEAD", r.Method)
|
||||
}
|
||||
switch r.URL.Path {
|
||||
case "/dir-with-nonce":
|
||||
w.Header().Set("Replay-Nonce", "dirnonce")
|
||||
case "/new-nonce":
|
||||
w.Header().Set("Replay-Nonce", "newnonce")
|
||||
case "/dir-no-nonce", "/empty":
|
||||
// No nonce in the header.
|
||||
default:
|
||||
t.Errorf("Unknown URL: %s", r.URL)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
ctx := context.Background()
|
||||
|
||||
tt := []struct {
|
||||
dirURL, popURL, nonce string
|
||||
wantOK bool
|
||||
}{
|
||||
{ts.URL + "/dir-with-nonce", ts.URL + "/new-nonce", "dirnonce", true},
|
||||
{ts.URL + "/dir-no-nonce", ts.URL + "/new-nonce", "newnonce", true},
|
||||
{ts.URL + "/dir-no-nonce", ts.URL + "/empty", "", false},
|
||||
}
|
||||
for _, test := range tt {
|
||||
t.Run(fmt.Sprintf("nonce:%s wantOK:%v", test.nonce, test.wantOK), func(t *testing.T) {
|
||||
c := Client{DirectoryURL: test.dirURL}
|
||||
v, err := c.popNonce(ctx, test.popURL)
|
||||
if !test.wantOK {
|
||||
if err == nil {
|
||||
t.Fatalf("c.popNonce(%q) returned nil error", test.popURL)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("c.popNonce(%q): %v", test.popURL, err)
|
||||
}
|
||||
if v != test.nonce {
|
||||
t.Errorf("c.popNonce(%q) = %q; want %q", test.popURL, v, test.nonce)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_postJWS(t *testing.T) {
|
||||
var count int
|
||||
seen := make(map[string]bool)
|
||||
@ -1046,7 +1133,11 @@ func TestNonce_postJWS(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
|
||||
client := Client{
|
||||
Key: testKey,
|
||||
DirectoryURL: ts.URL, // nonces are fetched from here first
|
||||
dir: &Directory{AuthzURL: ts.URL},
|
||||
}
|
||||
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||
t.Errorf("client.Authorize 1: %v", err)
|
||||
}
|
||||
@ -1068,44 +1159,6 @@ func TestNonce_postJWS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryPostJWS(t *testing.T) {
|
||||
var count int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
|
||||
if r.Method == "HEAD" {
|
||||
// We expect the client to do 2 head requests to fetch
|
||||
// nonces, one to start and another after getting badNonce
|
||||
return
|
||||
}
|
||||
|
||||
head, err := decodeJWSHead(r)
|
||||
if err != nil {
|
||||
t.Errorf("decodeJWSHead: %v", err)
|
||||
} else if head.Nonce == "" {
|
||||
t.Error("head.Nonce is empty")
|
||||
} else if head.Nonce == "nonce1" {
|
||||
// return a badNonce error to force the call to retry
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`))
|
||||
return
|
||||
}
|
||||
// Make client.Authorize happy; we're not testing its result.
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(`{"status":"valid"}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
|
||||
// This call will fail with badNonce, causing a retry
|
||||
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||
t.Errorf("client.Authorize 1: %v", err)
|
||||
}
|
||||
if count != 4 {
|
||||
t.Errorf("total requests count: %d; want 4", count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkHeader(t *testing.T) {
|
||||
h := http.Header{"Link": {
|
||||
`<https://example.com/acme/new-authz>;rel="next"`,
|
||||
@ -1129,37 +1182,6 @@ func TestLinkHeader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorResponse(t *testing.T) {
|
||||
s := `{
|
||||
"status": 400,
|
||||
"type": "urn:acme:error:xxx",
|
||||
"detail": "text"
|
||||
}`
|
||||
res := &http.Response{
|
||||
StatusCode: 400,
|
||||
Status: "400 Bad Request",
|
||||
Body: ioutil.NopCloser(strings.NewReader(s)),
|
||||
Header: http.Header{"X-Foo": {"bar"}},
|
||||
}
|
||||
err := responseError(res)
|
||||
v, ok := err.(*Error)
|
||||
if !ok {
|
||||
t.Fatalf("err = %+v (%T); want *Error type", err, err)
|
||||
}
|
||||
if v.StatusCode != 400 {
|
||||
t.Errorf("v.StatusCode = %v; want 400", v.StatusCode)
|
||||
}
|
||||
if v.ProblemType != "urn:acme:error:xxx" {
|
||||
t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType)
|
||||
}
|
||||
if v.Detail != "text" {
|
||||
t.Errorf("v.Detail = %q; want text", v.Detail)
|
||||
}
|
||||
if !reflect.DeepEqual(v.Header, res.Header) {
|
||||
t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSSNI01ChallengeCert(t *testing.T) {
|
||||
const (
|
||||
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
|
||||
@ -1227,6 +1249,58 @@ func TestTLSSNI02ChallengeCert(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSALPN01ChallengeCert(t *testing.T) {
|
||||
const (
|
||||
token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
|
||||
keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA." + testKeyECThumbprint
|
||||
// echo -n <token.testKeyECThumbprint> | shasum -a 256
|
||||
h = "0420dbbd5eefe7b4d06eb9d1d9f5acb4c7cda27d320e4b30332f0b6cb441734ad7b0"
|
||||
domain = "example.com"
|
||||
)
|
||||
|
||||
extValue, err := hex.DecodeString(h)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
client := &Client{Key: testKeyEC}
|
||||
tlscert, err := client.TLSALPN01ChallengeCert(token, domain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n := len(tlscert.Certificate); n != 1 {
|
||||
t.Fatalf("len(tlscert.Certificate) = %d; want 1", n)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(tlscert.Certificate[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
names := []string{domain}
|
||||
if !reflect.DeepEqual(cert.DNSNames, names) {
|
||||
t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names)
|
||||
}
|
||||
if cn := cert.Subject.CommonName; cn != domain {
|
||||
t.Errorf("CommonName = %q; want %q", cn, domain)
|
||||
}
|
||||
acmeExts := []pkix.Extension{}
|
||||
for _, ext := range cert.Extensions {
|
||||
if idPeACMEIdentifierV1.Equal(ext.Id) {
|
||||
acmeExts = append(acmeExts, ext)
|
||||
}
|
||||
}
|
||||
if len(acmeExts) != 1 {
|
||||
t.Errorf("acmeExts = %v; want exactly one", acmeExts)
|
||||
}
|
||||
if !acmeExts[0].Critical {
|
||||
t.Errorf("acmeExt.Critical = %v; want true", acmeExts[0].Critical)
|
||||
}
|
||||
if bytes.Compare(acmeExts[0].Value, extValue) != 0 {
|
||||
t.Errorf("acmeExt.Value = %v; want %v", acmeExts[0].Value, extValue)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestTLSChallengeCertOpt(t *testing.T) {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 512)
|
||||
if err != nil {
|
||||
@ -1325,28 +1399,3 @@ func TestDNS01ChallengeRecord(t *testing.T) {
|
||||
t.Errorf("val = %q; want %q", val, value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackoff(t *testing.T) {
|
||||
tt := []struct{ min, max time.Duration }{
|
||||
{time.Second, 2 * time.Second},
|
||||
{2 * time.Second, 3 * time.Second},
|
||||
{4 * time.Second, 5 * time.Second},
|
||||
{8 * time.Second, 9 * time.Second},
|
||||
}
|
||||
for i, test := range tt {
|
||||
d := backoff(i, time.Minute)
|
||||
if d < test.min || test.max < d {
|
||||
t.Errorf("%d: d = %v; want between %v and %v", i, d, test.min, test.max)
|
||||
}
|
||||
}
|
||||
|
||||
min, max := time.Second, 2*time.Second
|
||||
if d := backoff(-1, time.Minute); d < min || max < d {
|
||||
t.Errorf("d = %v; want between %v and %v", d, min, max)
|
||||
}
|
||||
|
||||
bound := 10 * time.Second
|
||||
if d := backoff(100, bound); d != bound {
|
||||
t.Errorf("d = %v; want %v", d, bound)
|
||||
}
|
||||
}
|
||||
|
372
vendor/golang.org/x/crypto/acme/autocert/autocert.go
generated
vendored
372
vendor/golang.org/x/crypto/acme/autocert/autocert.go
generated
vendored
@ -27,7 +27,6 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -45,7 +44,7 @@ var createCertRetryAfter = time.Minute
|
||||
var pseudoRand *lockedMathRand
|
||||
|
||||
func init() {
|
||||
src := mathrand.NewSource(timeNow().UnixNano())
|
||||
src := mathrand.NewSource(time.Now().UnixNano())
|
||||
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
|
||||
}
|
||||
|
||||
@ -70,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
|
||||
}
|
||||
@ -82,9 +81,9 @@ func defaultHostPolicy(context.Context, string) error {
|
||||
}
|
||||
|
||||
// Manager is a stateful certificate manager built on top of acme.Client.
|
||||
// It obtains and refreshes certificates automatically using "tls-sni-01",
|
||||
// "tls-sni-02" and "http-01" challenge types, as well as providing them
|
||||
// to a TLS server via tls.Config.
|
||||
// It obtains and refreshes certificates automatically using "tls-alpn-01",
|
||||
// "tls-sni-01", "tls-sni-02" and "http-01" challenge types,
|
||||
// as well as providing them to a TLS server via tls.Config.
|
||||
//
|
||||
// You must specify a cache implementation, such as DirCache,
|
||||
// to reuse obtained certificates across program restarts.
|
||||
@ -99,11 +98,11 @@ type Manager struct {
|
||||
// To always accept the terms, the callers can use AcceptTOS.
|
||||
Prompt func(tosURL string) bool
|
||||
|
||||
// Cache optionally stores and retrieves previously-obtained certificates.
|
||||
// If nil, certs will only be cached for the lifetime of the Manager.
|
||||
// Cache optionally stores and retrieves previously-obtained certificates
|
||||
// and other state. If nil, certs will only be cached for the lifetime of
|
||||
// the Manager. Multiple Managers can share the same Cache.
|
||||
//
|
||||
// Manager passes the Cache certificates data encoded in PEM, with private/public
|
||||
// parts combined in a single Cache.Put call, private key first.
|
||||
// Using a persistent Cache, such as DirCache, is strongly recommended.
|
||||
Cache Cache
|
||||
|
||||
// HostPolicy controls which domains the Manager will attempt
|
||||
@ -128,8 +127,10 @@ type Manager struct {
|
||||
|
||||
// Client is used to perform low-level operations, such as account registration
|
||||
// and requesting new certificates.
|
||||
//
|
||||
// If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
|
||||
// directory endpoint and a newly-generated ECDSA P-256 key.
|
||||
// as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is
|
||||
// generated and, if Cache is not nil, stored in cache.
|
||||
//
|
||||
// Mutating the field after the first call of GetCertificate method will have no effect.
|
||||
Client *acme.Client
|
||||
@ -141,22 +142,30 @@ type Manager struct {
|
||||
// If the Client's account key is already registered, Email is not used.
|
||||
Email string
|
||||
|
||||
// ForceRSA makes the Manager generate certificates with 2048-bit RSA keys.
|
||||
// ForceRSA used to make the Manager generate RSA certificates. It is now ignored.
|
||||
//
|
||||
// If false, a default is used. Currently the default
|
||||
// is EC-based keys using the P-256 curve.
|
||||
// Deprecated: the Manager will request the correct type of certificate based
|
||||
// on what each client supports.
|
||||
ForceRSA bool
|
||||
|
||||
// ExtraExtensions are used when generating a new CSR (Certificate Request),
|
||||
// thus allowing customization of the resulting certificate.
|
||||
// For instance, TLS Feature Extension (RFC 7633) can be used
|
||||
// to prevent an OCSP downgrade attack.
|
||||
//
|
||||
// The field value is passed to crypto/x509.CreateCertificateRequest
|
||||
// in the template's ExtraExtensions field as is.
|
||||
ExtraExtensions []pkix.Extension
|
||||
|
||||
clientMu sync.Mutex
|
||||
client *acme.Client // initialized by acmeClient method
|
||||
|
||||
stateMu sync.Mutex
|
||||
state map[string]*certState // keyed by domain name
|
||||
state map[certKey]*certState
|
||||
|
||||
// renewal tracks the set of domains currently running renewal timers.
|
||||
// It is keyed by domain name.
|
||||
renewalMu sync.Mutex
|
||||
renewal map[string]*domainRenewal
|
||||
renewal map[certKey]*domainRenewal
|
||||
|
||||
// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
|
||||
tokensMu sync.RWMutex
|
||||
@ -168,21 +177,60 @@ type Manager struct {
|
||||
// to be provisioned.
|
||||
// The entries are stored for the duration of the authorization flow.
|
||||
httpTokens map[string][]byte
|
||||
// certTokens contains temporary certificates for tls-sni challenges
|
||||
// certTokens contains temporary certificates for tls-sni and tls-alpn challenges
|
||||
// and is keyed by token domain name, which matches server name of ClientHello.
|
||||
// Keys always have ".acme.invalid" suffix.
|
||||
// Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names
|
||||
// for tls-alpn.
|
||||
// The entries are stored for the duration of the authorization flow.
|
||||
certTokens map[string]*tls.Certificate
|
||||
// nowFunc, if not nil, returns the current time. This may be set for
|
||||
// testing purposes.
|
||||
nowFunc func() time.Time
|
||||
}
|
||||
|
||||
// certKey is the key by which certificates are tracked in state, renewal and cache.
|
||||
type certKey struct {
|
||||
domain string // without trailing dot
|
||||
isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA)
|
||||
isToken bool // tls-based challenge token cert; key type is undefined regardless of isRSA
|
||||
}
|
||||
|
||||
func (c certKey) String() string {
|
||||
if c.isToken {
|
||||
return c.domain + "+token"
|
||||
}
|
||||
if c.isRSA {
|
||||
return c.domain + "+rsa"
|
||||
}
|
||||
return c.domain
|
||||
}
|
||||
|
||||
// TLSConfig creates a new TLS config suitable for net/http.Server servers,
|
||||
// supporting HTTP/2 and the tls-alpn-01 ACME challenge type.
|
||||
func (m *Manager) TLSConfig() *tls.Config {
|
||||
return &tls.Config{
|
||||
GetCertificate: m.GetCertificate,
|
||||
NextProtos: []string{
|
||||
"h2", "http/1.1", // enable HTTP/2
|
||||
acme.ALPNProto, // enable tls-alpn ACME challenges
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetCertificate implements the tls.Config.GetCertificate hook.
|
||||
// It provides a TLS certificate for hello.ServerName host, including answering
|
||||
// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored.
|
||||
// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges.
|
||||
// All other fields of hello are ignored.
|
||||
//
|
||||
// If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
|
||||
// a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation.
|
||||
// The error is propagated back to the caller of GetCertificate and is user-visible.
|
||||
// This does not affect cached certs. See HostPolicy field description for more details.
|
||||
//
|
||||
// If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will
|
||||
// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler
|
||||
// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers
|
||||
// due to security issues in the ecosystem.)
|
||||
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
if m.Prompt == nil {
|
||||
return nil, errors.New("acme/autocert: Manager.Prompt not set")
|
||||
@ -195,7 +243,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||
if !strings.Contains(strings.Trim(name, "."), ".") {
|
||||
return nil, errors.New("acme/autocert: server name component count invalid")
|
||||
}
|
||||
if strings.ContainsAny(name, `/\`) {
|
||||
if strings.ContainsAny(name, `+/\`) {
|
||||
return nil, errors.New("acme/autocert: server name contains invalid character")
|
||||
}
|
||||
|
||||
@ -204,14 +252,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// check whether this is a token cert requested for TLS-SNI challenge
|
||||
if strings.HasSuffix(name, ".acme.invalid") {
|
||||
// Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge.
|
||||
if wantsTokenCert(hello) {
|
||||
m.tokensMu.RLock()
|
||||
defer m.tokensMu.RUnlock()
|
||||
// It's ok to use the same token cert key for both tls-sni and tls-alpn
|
||||
// because there's always at most 1 token cert per on-going domain authorization.
|
||||
// See m.verify for details.
|
||||
if cert := m.certTokens[name]; cert != nil {
|
||||
return cert, nil
|
||||
}
|
||||
if cert, err := m.cacheGet(ctx, name); err == nil {
|
||||
if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil {
|
||||
return cert, nil
|
||||
}
|
||||
// TODO: cache error results?
|
||||
@ -219,8 +270,11 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||
}
|
||||
|
||||
// regular domain
|
||||
name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
|
||||
cert, err := m.cert(ctx, name)
|
||||
ck := certKey{
|
||||
domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114
|
||||
isRSA: !supportsECDSA(hello),
|
||||
}
|
||||
cert, err := m.cert(ctx, ck)
|
||||
if err == nil {
|
||||
return cert, nil
|
||||
}
|
||||
@ -232,14 +286,71 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||
if err := m.hostPolicy()(ctx, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert, err = m.createCert(ctx, name)
|
||||
cert, err = m.createCert(ctx, ck)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.cachePut(ctx, name, cert)
|
||||
m.cachePut(ctx, ck, cert)
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// wantsTokenCert reports whether a TLS request with SNI is made by a CA server
|
||||
// for a challenge verification.
|
||||
func wantsTokenCert(hello *tls.ClientHelloInfo) bool {
|
||||
// tls-alpn-01
|
||||
if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto {
|
||||
return true
|
||||
}
|
||||
// tls-sni-xx
|
||||
return strings.HasSuffix(hello.ServerName, ".acme.invalid")
|
||||
}
|
||||
|
||||
func supportsECDSA(hello *tls.ClientHelloInfo) bool {
|
||||
// The "signature_algorithms" extension, if present, limits the key exchange
|
||||
// algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1.
|
||||
if hello.SignatureSchemes != nil {
|
||||
ecdsaOK := false
|
||||
schemeLoop:
|
||||
for _, scheme := range hello.SignatureSchemes {
|
||||
const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10
|
||||
switch scheme {
|
||||
case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256,
|
||||
tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512:
|
||||
ecdsaOK = true
|
||||
break schemeLoop
|
||||
}
|
||||
}
|
||||
if !ecdsaOK {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if hello.SupportedCurves != nil {
|
||||
ecdsaOK := false
|
||||
for _, curve := range hello.SupportedCurves {
|
||||
if curve == tls.CurveP256 {
|
||||
ecdsaOK = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ecdsaOK {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, suite := range hello.CipherSuites {
|
||||
switch suite {
|
||||
case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
|
||||
// It returns an http.Handler that responds to the challenges and must be
|
||||
// running on port 80. If it receives a request that is not an ACME challenge,
|
||||
@ -253,8 +364,8 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||
// Because the fallback handler is run with unencrypted port 80 requests,
|
||||
// the fallback should not serve TLS-only requests.
|
||||
//
|
||||
// If HTTPHandler is never called, the Manager will only use TLS SNI
|
||||
// challenges for domain verification.
|
||||
// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01"
|
||||
// challenge for domain verification.
|
||||
func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
|
||||
m.tokensMu.Lock()
|
||||
defer m.tokensMu.Unlock()
|
||||
@ -305,16 +416,16 @@ func stripPort(hostport string) string {
|
||||
// cert returns an existing certificate either from m.state or cache.
|
||||
// If a certificate is found in cache but not in m.state, the latter will be filled
|
||||
// with the cached value.
|
||||
func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, error) {
|
||||
func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
|
||||
m.stateMu.Lock()
|
||||
if s, ok := m.state[name]; ok {
|
||||
if s, ok := m.state[ck]; ok {
|
||||
m.stateMu.Unlock()
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
return s.tlscert()
|
||||
}
|
||||
defer m.stateMu.Unlock()
|
||||
cert, err := m.cacheGet(ctx, name)
|
||||
cert, err := m.cacheGet(ctx, ck)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -323,25 +434,25 @@ func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, erro
|
||||
return nil, errors.New("acme/autocert: private key cannot sign")
|
||||
}
|
||||
if m.state == nil {
|
||||
m.state = make(map[string]*certState)
|
||||
m.state = make(map[certKey]*certState)
|
||||
}
|
||||
s := &certState{
|
||||
key: signer,
|
||||
cert: cert.Certificate,
|
||||
leaf: cert.Leaf,
|
||||
}
|
||||
m.state[name] = s
|
||||
go m.renew(name, s.key, s.leaf.NotAfter)
|
||||
m.state[ck] = s
|
||||
go m.renew(ck, s.key, s.leaf.NotAfter)
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// cacheGet always returns a valid certificate, or an error otherwise.
|
||||
// If a cached certficate exists but is not valid, ErrCacheMiss is returned.
|
||||
func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate, error) {
|
||||
// If a cached certificate exists but is not valid, ErrCacheMiss is returned.
|
||||
func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) {
|
||||
if m.Cache == nil {
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
data, err := m.Cache.Get(ctx, domain)
|
||||
data, err := m.Cache.Get(ctx, ck.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -372,7 +483,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate
|
||||
}
|
||||
|
||||
// verify and create TLS cert
|
||||
leaf, err := validCert(domain, pubDER, privKey)
|
||||
leaf, err := validCert(ck, pubDER, privKey, m.now())
|
||||
if err != nil {
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
@ -384,7 +495,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate
|
||||
return tlscert, nil
|
||||
}
|
||||
|
||||
func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error {
|
||||
func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error {
|
||||
if m.Cache == nil {
|
||||
return nil
|
||||
}
|
||||
@ -416,7 +527,7 @@ func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Cert
|
||||
}
|
||||
}
|
||||
|
||||
return m.Cache.Put(ctx, domain, buf.Bytes())
|
||||
return m.Cache.Put(ctx, ck.String(), buf.Bytes())
|
||||
}
|
||||
|
||||
func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
|
||||
@ -433,9 +544,9 @@ func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error {
|
||||
//
|
||||
// If the domain is already being verified, it waits for the existing verification to complete.
|
||||
// Either way, createCert blocks for the duration of the whole process.
|
||||
func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) {
|
||||
func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) {
|
||||
// TODO: maybe rewrite this whole piece using sync.Once
|
||||
state, err := m.certState(domain)
|
||||
state, err := m.certState(ck)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -453,44 +564,44 @@ func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certifica
|
||||
defer state.Unlock()
|
||||
state.locked = false
|
||||
|
||||
der, leaf, err := m.authorizedCert(ctx, state.key, domain)
|
||||
der, leaf, err := m.authorizedCert(ctx, state.key, ck)
|
||||
if err != nil {
|
||||
// Remove the failed state after some time,
|
||||
// making the manager call createCert again on the following TLS hello.
|
||||
time.AfterFunc(createCertRetryAfter, func() {
|
||||
defer testDidRemoveState(domain)
|
||||
defer testDidRemoveState(ck)
|
||||
m.stateMu.Lock()
|
||||
defer m.stateMu.Unlock()
|
||||
// Verify the state hasn't changed and it's still invalid
|
||||
// before deleting.
|
||||
s, ok := m.state[domain]
|
||||
s, ok := m.state[ck]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if _, err := validCert(domain, s.cert, s.key); err == nil {
|
||||
if _, err := validCert(ck, s.cert, s.key, m.now()); err == nil {
|
||||
return
|
||||
}
|
||||
delete(m.state, domain)
|
||||
delete(m.state, ck)
|
||||
})
|
||||
return nil, err
|
||||
}
|
||||
state.cert = der
|
||||
state.leaf = leaf
|
||||
go m.renew(domain, state.key, state.leaf.NotAfter)
|
||||
go m.renew(ck, state.key, state.leaf.NotAfter)
|
||||
return state.tlscert()
|
||||
}
|
||||
|
||||
// certState returns a new or existing certState.
|
||||
// If a new certState is returned, state.exist is false and the state is locked.
|
||||
// The returned error is non-nil only in the case where a new state could not be created.
|
||||
func (m *Manager) certState(domain string) (*certState, error) {
|
||||
func (m *Manager) certState(ck certKey) (*certState, error) {
|
||||
m.stateMu.Lock()
|
||||
defer m.stateMu.Unlock()
|
||||
if m.state == nil {
|
||||
m.state = make(map[string]*certState)
|
||||
m.state = make(map[certKey]*certState)
|
||||
}
|
||||
// existing state
|
||||
if state, ok := m.state[domain]; ok {
|
||||
if state, ok := m.state[ck]; ok {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
@ -499,7 +610,7 @@ func (m *Manager) certState(domain string) (*certState, error) {
|
||||
err error
|
||||
key crypto.Signer
|
||||
)
|
||||
if m.ForceRSA {
|
||||
if ck.isRSA {
|
||||
key, err = rsa.GenerateKey(rand.Reader, 2048)
|
||||
} else {
|
||||
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
@ -513,22 +624,22 @@ func (m *Manager) certState(domain string) (*certState, error) {
|
||||
locked: true,
|
||||
}
|
||||
state.Lock() // will be unlocked by m.certState caller
|
||||
m.state[domain] = state
|
||||
m.state[ck] = state
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// authorizedCert starts the domain ownership verification process and requests a new cert upon success.
|
||||
// The key argument is the certificate private key.
|
||||
func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
|
||||
func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) {
|
||||
client, err := m.acmeClient(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := m.verify(ctx, client, domain); err != nil {
|
||||
if err := m.verify(ctx, client, ck.domain); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
csr, err := certRequest(key, domain)
|
||||
csr, err := certRequest(key, ck.domain, m.ExtraExtensions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -536,25 +647,55 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
leaf, err = validCert(domain, der, key)
|
||||
leaf, err = validCert(ck, der, key, m.now())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return der, leaf, nil
|
||||
}
|
||||
|
||||
// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice.
|
||||
// It ignores revocation errors.
|
||||
func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) {
|
||||
client, err := m.acmeClient(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, u := range uri {
|
||||
client.RevokeAuthorization(ctx, u)
|
||||
}
|
||||
}
|
||||
|
||||
// verify runs the identifier (domain) authorization flow
|
||||
// using each applicable ACME challenge type.
|
||||
func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
|
||||
// The list of challenge types we'll try to fulfill
|
||||
// in this specific order.
|
||||
challengeTypes := []string{"tls-sni-02", "tls-sni-01"}
|
||||
challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"}
|
||||
m.tokensMu.RLock()
|
||||
if m.tryHTTP01 {
|
||||
challengeTypes = append(challengeTypes, "http-01")
|
||||
}
|
||||
m.tokensMu.RUnlock()
|
||||
|
||||
// Keep track of pending authzs and revoke the ones that did not validate.
|
||||
pendingAuthzs := make(map[string]bool)
|
||||
defer func() {
|
||||
var uri []string
|
||||
for k, pending := range pendingAuthzs {
|
||||
if pending {
|
||||
uri = append(uri, k)
|
||||
}
|
||||
}
|
||||
if len(uri) > 0 {
|
||||
// Use "detached" background context.
|
||||
// The revocations need not happen in the current verification flow.
|
||||
go m.revokePendingAuthz(context.Background(), uri)
|
||||
}
|
||||
}()
|
||||
|
||||
// errs accumulates challenge failure errors, printed if all fail
|
||||
errs := make(map[*acme.Challenge]error)
|
||||
var nextTyp int // challengeType index of the next challenge type to try
|
||||
for {
|
||||
// Start domain authorization and get the challenge.
|
||||
@ -571,6 +712,8 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
|
||||
return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI)
|
||||
}
|
||||
|
||||
pendingAuthzs[authz.URI] = true
|
||||
|
||||
// Pick the next preferred challenge.
|
||||
var chal *acme.Challenge
|
||||
for chal == nil && nextTyp < len(challengeTypes) {
|
||||
@ -578,28 +721,44 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
|
||||
nextTyp++
|
||||
}
|
||||
if chal == nil {
|
||||
return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes)
|
||||
errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain)
|
||||
for chal, err := range errs {
|
||||
errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err)
|
||||
}
|
||||
return errors.New(errorMsg)
|
||||
}
|
||||
cleanup, err := m.fulfill(ctx, client, chal)
|
||||
cleanup, err := m.fulfill(ctx, client, chal, domain)
|
||||
if err != nil {
|
||||
errs[chal] = err
|
||||
continue
|
||||
}
|
||||
defer cleanup()
|
||||
if _, err := client.Accept(ctx, chal); err != nil {
|
||||
errs[chal] = err
|
||||
continue
|
||||
}
|
||||
|
||||
// A challenge is fulfilled and accepted: wait for the CA to validate.
|
||||
if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil {
|
||||
return nil
|
||||
if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil {
|
||||
errs[chal] = err
|
||||
continue
|
||||
}
|
||||
delete(pendingAuthzs, authz.URI)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// fulfill provisions a response to the challenge chal.
|
||||
// The cleanup is non-nil only if provisioning succeeded.
|
||||
func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge) (cleanup func(), err error) {
|
||||
func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) {
|
||||
switch chal.Type {
|
||||
case "tls-alpn-01":
|
||||
cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.putCertToken(ctx, domain, &cert)
|
||||
return func() { go m.deleteCertToken(domain) }, nil
|
||||
case "tls-sni-01":
|
||||
cert, name, err := client.TLSSNI01ChallengeCert(chal.Token)
|
||||
if err != nil {
|
||||
@ -635,8 +794,8 @@ func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
|
||||
return nil
|
||||
}
|
||||
|
||||
// putCertToken stores the cert under the named key in both m.certTokens map
|
||||
// and m.Cache.
|
||||
// putCertToken stores the token certificate with the specified name
|
||||
// in both m.certTokens map and m.Cache.
|
||||
func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) {
|
||||
m.tokensMu.Lock()
|
||||
defer m.tokensMu.Unlock()
|
||||
@ -644,17 +803,18 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi
|
||||
m.certTokens = make(map[string]*tls.Certificate)
|
||||
}
|
||||
m.certTokens[name] = cert
|
||||
m.cachePut(ctx, name, cert)
|
||||
m.cachePut(ctx, certKey{domain: name, isToken: true}, cert)
|
||||
}
|
||||
|
||||
// deleteCertToken removes the token certificate for the specified domain name
|
||||
// deleteCertToken removes the token certificate with the specified name
|
||||
// from both m.certTokens map and m.Cache.
|
||||
func (m *Manager) deleteCertToken(name string) {
|
||||
m.tokensMu.Lock()
|
||||
defer m.tokensMu.Unlock()
|
||||
delete(m.certTokens, name)
|
||||
if m.Cache != nil {
|
||||
m.Cache.Delete(context.Background(), name)
|
||||
ck := certKey{domain: name, isToken: true}
|
||||
m.Cache.Delete(context.Background(), ck.String())
|
||||
}
|
||||
}
|
||||
|
||||
@ -705,7 +865,7 @@ func (m *Manager) deleteHTTPToken(tokenPath string) {
|
||||
// httpTokenCacheKey returns a key at which an http-01 token value may be stored
|
||||
// in the Manager's optional Cache.
|
||||
func httpTokenCacheKey(tokenPath string) string {
|
||||
return "http-01-" + path.Base(tokenPath)
|
||||
return path.Base(tokenPath) + "+http-01"
|
||||
}
|
||||
|
||||
// renew starts a cert renewal timer loop, one per domain.
|
||||
@ -716,18 +876,18 @@ func httpTokenCacheKey(tokenPath string) string {
|
||||
//
|
||||
// The key argument is a certificate private key.
|
||||
// The exp argument is the cert expiration time (NotAfter).
|
||||
func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) {
|
||||
func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) {
|
||||
m.renewalMu.Lock()
|
||||
defer m.renewalMu.Unlock()
|
||||
if m.renewal[domain] != nil {
|
||||
if m.renewal[ck] != nil {
|
||||
// another goroutine is already on it
|
||||
return
|
||||
}
|
||||
if m.renewal == nil {
|
||||
m.renewal = make(map[string]*domainRenewal)
|
||||
m.renewal = make(map[certKey]*domainRenewal)
|
||||
}
|
||||
dr := &domainRenewal{m: m, domain: domain, key: key}
|
||||
m.renewal[domain] = dr
|
||||
dr := &domainRenewal{m: m, ck: ck, key: key}
|
||||
m.renewal[ck] = dr
|
||||
dr.start(exp)
|
||||
}
|
||||
|
||||
@ -743,7 +903,10 @@ func (m *Manager) stopRenew() {
|
||||
}
|
||||
|
||||
func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
|
||||
const keyName = "acme_account.key"
|
||||
const keyName = "acme_account+key"
|
||||
|
||||
// Previous versions of autocert stored the value under a different key.
|
||||
const legacyKeyName = "acme_account.key"
|
||||
|
||||
genKey := func() (*ecdsa.PrivateKey, error) {
|
||||
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
@ -754,6 +917,9 @@ func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) {
|
||||
}
|
||||
|
||||
data, err := m.Cache.Get(ctx, keyName)
|
||||
if err == ErrCacheMiss {
|
||||
data, err = m.Cache.Get(ctx, legacyKeyName)
|
||||
}
|
||||
if err == ErrCacheMiss {
|
||||
key, err := genKey()
|
||||
if err != nil {
|
||||
@ -825,6 +991,13 @@ func (m *Manager) renewBefore() time.Duration {
|
||||
return 720 * time.Hour // 30 days
|
||||
}
|
||||
|
||||
func (m *Manager) now() time.Time {
|
||||
if m.nowFunc != nil {
|
||||
return m.nowFunc()
|
||||
}
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// certState is ready when its mutex is unlocked for reading.
|
||||
type certState struct {
|
||||
sync.RWMutex
|
||||
@ -850,12 +1023,12 @@ func (s *certState) tlscert() (*tls.Certificate, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// certRequest creates a certificate request for the given common name cn
|
||||
// and optional SANs.
|
||||
func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) {
|
||||
// certRequest generates a CSR for the given common name cn and optional SANs.
|
||||
func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) {
|
||||
req := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{CommonName: cn},
|
||||
DNSNames: san,
|
||||
Subject: pkix.Name{CommonName: cn},
|
||||
DNSNames: san,
|
||||
ExtraExtensions: ext,
|
||||
}
|
||||
return x509.CreateCertificateRequest(rand.Reader, req, key)
|
||||
}
|
||||
@ -886,12 +1059,12 @@ func parsePrivateKey(der []byte) (crypto.Signer, error) {
|
||||
return nil, errors.New("acme/autocert: failed to parse private key")
|
||||
}
|
||||
|
||||
// validCert parses a cert chain provided as der argument and verifies the leaf, der[0],
|
||||
// corresponds to the private key, as well as the domain match and expiration dates.
|
||||
// It doesn't do any revocation checking.
|
||||
// validCert parses a cert chain provided as der argument and verifies the leaf and der[0]
|
||||
// correspond to the private key, the domain and key type match, and expiration dates
|
||||
// are valid. It doesn't do any revocation checking.
|
||||
//
|
||||
// The returned value is the verified leaf cert.
|
||||
func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) {
|
||||
func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) {
|
||||
// parse public part(s)
|
||||
var n int
|
||||
for _, b := range der {
|
||||
@ -903,22 +1076,21 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
|
||||
n += copy(pub[n:], b)
|
||||
}
|
||||
x509Cert, err := x509.ParseCertificates(pub)
|
||||
if len(x509Cert) == 0 {
|
||||
if err != nil || len(x509Cert) == 0 {
|
||||
return nil, errors.New("acme/autocert: no public key found")
|
||||
}
|
||||
// verify the leaf is not expired and matches the domain name
|
||||
leaf = x509Cert[0]
|
||||
now := timeNow()
|
||||
if now.Before(leaf.NotBefore) {
|
||||
return nil, errors.New("acme/autocert: certificate is not valid yet")
|
||||
}
|
||||
if now.After(leaf.NotAfter) {
|
||||
return nil, errors.New("acme/autocert: expired certificate")
|
||||
}
|
||||
if err := leaf.VerifyHostname(domain); err != nil {
|
||||
if err := leaf.VerifyHostname(ck.domain); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// ensure the leaf corresponds to the private key
|
||||
// ensure the leaf corresponds to the private key and matches the certKey type
|
||||
switch pub := leaf.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
prv, ok := key.(*rsa.PrivateKey)
|
||||
@ -928,6 +1100,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
|
||||
if pub.N.Cmp(prv.N) != 0 {
|
||||
return nil, errors.New("acme/autocert: private key does not match public key")
|
||||
}
|
||||
if !ck.isRSA && !ck.isToken {
|
||||
return nil, errors.New("acme/autocert: key type does not match expected value")
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
prv, ok := key.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
@ -936,22 +1111,15 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi
|
||||
if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 {
|
||||
return nil, errors.New("acme/autocert: private key does not match public key")
|
||||
}
|
||||
if ck.isRSA && !ck.isToken {
|
||||
return nil, errors.New("acme/autocert: key type does not match expected value")
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("acme/autocert: unknown public key algorithm")
|
||||
}
|
||||
return leaf, nil
|
||||
}
|
||||
|
||||
func retryAfter(v string) time.Duration {
|
||||
if i, err := strconv.Atoi(v); err == nil {
|
||||
return time.Duration(i) * time.Second
|
||||
}
|
||||
if t, err := http.ParseTime(v); err == nil {
|
||||
return t.Sub(timeNow())
|
||||
}
|
||||
return time.Second
|
||||
}
|
||||
|
||||
type lockedMathRand struct {
|
||||
sync.Mutex
|
||||
rnd *mathrand.Rand
|
||||
@ -966,8 +1134,6 @@ func (r *lockedMathRand) int63n(max int64) int64 {
|
||||
|
||||
// For easier testing.
|
||||
var (
|
||||
timeNow = time.Now
|
||||
|
||||
// Called when a state is removed.
|
||||
testDidRemoveState = func(domain string) {}
|
||||
testDidRemoveState = func(certKey) {}
|
||||
)
|
||||
|
624
vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
generated
vendored
624
vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
generated
vendored
@ -5,6 +5,7 @@
|
||||
package autocert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
@ -14,11 +15,13 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@ -29,6 +32,13 @@ import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/acme"
|
||||
"golang.org/x/crypto/acme/autocert/internal/acmetest"
|
||||
)
|
||||
|
||||
var (
|
||||
exampleDomain = "example.org"
|
||||
exampleCertKey = certKey{domain: exampleDomain}
|
||||
exampleCertKeyRSA = certKey{domain: exampleDomain, isRSA: true}
|
||||
)
|
||||
|
||||
var discoTmpl = template.Must(template.New("disco").Parse(`{
|
||||
@ -64,6 +74,7 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{
|
||||
}`))
|
||||
|
||||
type memCache struct {
|
||||
t *testing.T
|
||||
mu sync.Mutex
|
||||
keyData map[string][]byte
|
||||
}
|
||||
@ -79,7 +90,26 @@ func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// filenameSafe returns whether all characters in s are printable ASCII
|
||||
// and safe to use in a filename on most filesystems.
|
||||
func filenameSafe(s string) bool {
|
||||
for _, c := range s {
|
||||
if c < 0x20 || c > 0x7E {
|
||||
return false
|
||||
}
|
||||
switch c {
|
||||
case '\\', '/', ':', '*', '?', '"', '<', '>', '|':
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *memCache) Put(ctx context.Context, key string, data []byte) error {
|
||||
if !filenameSafe(key) {
|
||||
m.t.Errorf("invalid characters in cache key %q", key)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
@ -95,12 +125,29 @@ func (m *memCache) Delete(ctx context.Context, key string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMemCache() *memCache {
|
||||
func newMemCache(t *testing.T) *memCache {
|
||||
return &memCache{
|
||||
t: t,
|
||||
keyData: make(map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *memCache) numCerts() int {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
res := 0
|
||||
for key := range m.keyData {
|
||||
if strings.HasSuffix(key, "+token") ||
|
||||
strings.HasSuffix(key, "+key") ||
|
||||
strings.HasSuffix(key, "+http-01") {
|
||||
continue
|
||||
}
|
||||
res++
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func dummyCert(pub interface{}, san ...string) ([]byte, error) {
|
||||
return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
|
||||
}
|
||||
@ -137,53 +184,58 @@ func decodePayload(v interface{}, r io.Reader) error {
|
||||
return json.Unmarshal(payload, v)
|
||||
}
|
||||
|
||||
func clientHelloInfo(sni string, ecdsaSupport bool) *tls.ClientHelloInfo {
|
||||
hello := &tls.ClientHelloInfo{
|
||||
ServerName: sni,
|
||||
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
|
||||
}
|
||||
if ecdsaSupport {
|
||||
hello.CipherSuites = append(hello.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
|
||||
}
|
||||
return hello
|
||||
}
|
||||
|
||||
func TestGetCertificate(t *testing.T) {
|
||||
man := &Manager{Prompt: AcceptTOS}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
hello := clientHelloInfo("example.org", true)
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
}
|
||||
|
||||
func TestGetCertificate_trailingDot(t *testing.T) {
|
||||
man := &Manager{Prompt: AcceptTOS}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org."}
|
||||
hello := clientHelloInfo("example.org.", true)
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
}
|
||||
|
||||
func TestGetCertificate_ForceRSA(t *testing.T) {
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: newMemCache(),
|
||||
Cache: newMemCache(t),
|
||||
ForceRSA: true,
|
||||
}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
hello := clientHelloInfo(exampleDomain, true)
|
||||
testGetCertificate(t, man, exampleDomain, hello)
|
||||
|
||||
cert, err := man.cacheGet(context.Background(), "example.org")
|
||||
// ForceRSA was deprecated and is now ignored.
|
||||
cert, err := man.cacheGet(context.Background(), exampleCertKey)
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
if _, ok := cert.PrivateKey.(*rsa.PrivateKey); !ok {
|
||||
t.Errorf("cert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey)
|
||||
if _, ok := cert.PrivateKey.(*ecdsa.PrivateKey); !ok {
|
||||
t.Errorf("cert.PrivateKey is %T; want *ecdsa.PrivateKey", cert.PrivateKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCertificate_nilPrompt(t *testing.T) {
|
||||
man := &Manager{}
|
||||
defer man.stopRenew()
|
||||
url, finish := startACMEServerStub(t, man, "example.org")
|
||||
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
|
||||
defer finish()
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
man.Client = &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: url,
|
||||
}
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
man.Client = &acme.Client{DirectoryURL: url}
|
||||
hello := clientHelloInfo("example.org", true)
|
||||
if _, err := man.GetCertificate(hello); err == nil {
|
||||
t.Error("got certificate for example.org; wanted error")
|
||||
}
|
||||
@ -197,7 +249,7 @@ func TestGetCertificate_expiredCache(t *testing.T) {
|
||||
}
|
||||
tmpl := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
Subject: pkix.Name{CommonName: exampleDomain},
|
||||
NotAfter: time.Now(),
|
||||
}
|
||||
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
|
||||
@ -209,16 +261,16 @@ func TestGetCertificate_expiredCache(t *testing.T) {
|
||||
PrivateKey: pk,
|
||||
}
|
||||
|
||||
man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()}
|
||||
man := &Manager{Prompt: AcceptTOS, Cache: newMemCache(t)}
|
||||
defer man.stopRenew()
|
||||
if err := man.cachePut(context.Background(), "example.org", tlscert); err != nil {
|
||||
if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil {
|
||||
t.Fatalf("man.cachePut: %v", err)
|
||||
}
|
||||
|
||||
// The expired cached cert should trigger a new cert issuance
|
||||
// and return without an error.
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
hello := clientHelloInfo(exampleDomain, true)
|
||||
testGetCertificate(t, man, exampleDomain, hello)
|
||||
}
|
||||
|
||||
func TestGetCertificate_failedAttempt(t *testing.T) {
|
||||
@ -227,7 +279,6 @@ func TestGetCertificate_failedAttempt(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
const example = "example.org"
|
||||
d := createCertRetryAfter
|
||||
f := testDidRemoveState
|
||||
defer func() {
|
||||
@ -236,51 +287,168 @@ func TestGetCertificate_failedAttempt(t *testing.T) {
|
||||
}()
|
||||
createCertRetryAfter = 0
|
||||
done := make(chan struct{})
|
||||
testDidRemoveState = func(domain string) {
|
||||
if domain != example {
|
||||
t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example)
|
||||
testDidRemoveState = func(ck certKey) {
|
||||
if ck != exampleCertKey {
|
||||
t.Errorf("testDidRemoveState: domain = %v; want %v", ck, exampleCertKey)
|
||||
}
|
||||
close(done)
|
||||
}
|
||||
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Client: &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: ts.URL,
|
||||
},
|
||||
}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: example}
|
||||
hello := clientHelloInfo(exampleDomain, true)
|
||||
if _, err := man.GetCertificate(hello); err == nil {
|
||||
t.Error("GetCertificate: err is nil")
|
||||
}
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Errorf("took too long to remove the %q state", example)
|
||||
t.Errorf("took too long to remove the %q state", exampleCertKey)
|
||||
case <-done:
|
||||
man.stateMu.Lock()
|
||||
defer man.stateMu.Unlock()
|
||||
if v, exist := man.state[example]; exist {
|
||||
t.Errorf("state exists for %q: %+v", example, v)
|
||||
if v, exist := man.state[exampleCertKey]; exist {
|
||||
t.Errorf("state exists for %v: %+v", exampleCertKey, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testGetCertificate_tokenCache tests the fallback of token certificate fetches
|
||||
// to cache when Manager.certTokens misses. ecdsaSupport refers to the CA when
|
||||
// verifying the certificate token.
|
||||
func testGetCertificate_tokenCache(t *testing.T, ecdsaSupport bool) {
|
||||
man1 := &Manager{
|
||||
Cache: newMemCache(t),
|
||||
Prompt: AcceptTOS,
|
||||
}
|
||||
defer man1.stopRenew()
|
||||
man2 := &Manager{
|
||||
Cache: man1.Cache,
|
||||
Prompt: AcceptTOS,
|
||||
}
|
||||
defer man2.stopRenew()
|
||||
|
||||
// Send the verification request to a different Manager from the one that
|
||||
// initiated the authorization, when they share caches.
|
||||
url, finish := startACMEServerStub(t, getCertificateFromManager(man2, ecdsaSupport), "example.org")
|
||||
defer finish()
|
||||
man1.Client = &acme.Client{DirectoryURL: url}
|
||||
hello := clientHelloInfo("example.org", true)
|
||||
if _, err := man1.GetCertificate(hello); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := man2.GetCertificate(hello); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCertificate_tokenCache(t *testing.T) {
|
||||
t.Run("ecdsaSupport=true", func(t *testing.T) {
|
||||
testGetCertificate_tokenCache(t, true)
|
||||
})
|
||||
t.Run("ecdsaSupport=false", func(t *testing.T) {
|
||||
testGetCertificate_tokenCache(t, false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetCertificate_ecdsaVsRSA(t *testing.T) {
|
||||
cache := newMemCache(t)
|
||||
man := &Manager{Prompt: AcceptTOS, Cache: cache}
|
||||
defer man.stopRenew()
|
||||
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
|
||||
defer finish()
|
||||
man.Client = &acme.Client{DirectoryURL: url}
|
||||
|
||||
cert, err := man.GetCertificate(clientHelloInfo("example.org", true))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok {
|
||||
t.Error("an ECDSA client was served a non-ECDSA certificate")
|
||||
}
|
||||
|
||||
cert, err = man.GetCertificate(clientHelloInfo("example.org", false))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, ok := cert.Leaf.PublicKey.(*rsa.PublicKey); !ok {
|
||||
t.Error("a RSA client was served a non-RSA certificate")
|
||||
}
|
||||
|
||||
if _, err := man.GetCertificate(clientHelloInfo("example.org", true)); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, err := man.GetCertificate(clientHelloInfo("example.org", false)); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if numCerts := cache.numCerts(); numCerts != 2 {
|
||||
t.Errorf("found %d certificates in cache; want %d", numCerts, 2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCertificate_wrongCacheKeyType(t *testing.T) {
|
||||
cache := newMemCache(t)
|
||||
man := &Manager{Prompt: AcceptTOS, Cache: cache}
|
||||
defer man.stopRenew()
|
||||
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), exampleDomain)
|
||||
defer finish()
|
||||
man.Client = &acme.Client{DirectoryURL: url}
|
||||
|
||||
// Make an RSA cert and cache it without suffix.
|
||||
pk, err := rsa.GenerateKey(rand.Reader, 512)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tmpl := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{CommonName: exampleDomain},
|
||||
NotAfter: time.Now().Add(90 * 24 * time.Hour),
|
||||
}
|
||||
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rsaCert := &tls.Certificate{
|
||||
Certificate: [][]byte{pub},
|
||||
PrivateKey: pk,
|
||||
}
|
||||
if err := man.cachePut(context.Background(), exampleCertKey, rsaCert); err != nil {
|
||||
t.Fatalf("man.cachePut: %v", err)
|
||||
}
|
||||
|
||||
// The RSA cached cert should be silently ignored and replaced.
|
||||
cert, err := man.GetCertificate(clientHelloInfo(exampleDomain, true))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok {
|
||||
t.Error("an ECDSA client was served a non-ECDSA certificate")
|
||||
}
|
||||
if numCerts := cache.numCerts(); numCerts != 1 {
|
||||
t.Errorf("found %d certificates in cache; want %d", numCerts, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func getCertificateFromManager(man *Manager, ecdsaSupport bool) func(string) error {
|
||||
return func(sni string) error {
|
||||
_, err := man.GetCertificate(clientHelloInfo(sni, ecdsaSupport))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// startACMEServerStub runs an ACME server
|
||||
// The domain argument is the expected domain name of a certificate request.
|
||||
func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) {
|
||||
// TODO: Drop this in favour of x/crypto/acme/autocert/internal/acmetest.
|
||||
func startACMEServerStub(t *testing.T, getCertificate func(string) error, domain string) (url string, finish func()) {
|
||||
// echo token-02 | shasum -a 256
|
||||
// then divide result in 2 parts separated by dot
|
||||
tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
|
||||
verifyTokenCert := func() {
|
||||
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
|
||||
_, err := man.GetCertificate(hello)
|
||||
if err != nil {
|
||||
if err := getCertificate(tokenCertName); err != nil {
|
||||
t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
|
||||
return
|
||||
}
|
||||
@ -362,8 +530,7 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string,
|
||||
tick := time.NewTicker(100 * time.Millisecond)
|
||||
defer tick.Stop()
|
||||
for {
|
||||
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
|
||||
if _, err := man.GetCertificate(hello); err != nil {
|
||||
if err := getCertificate(tokenCertName); err != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
@ -387,21 +554,13 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string,
|
||||
// tests man.GetCertificate flow using the provided hello argument.
|
||||
// The domain argument is the expected domain name of a certificate request.
|
||||
func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) {
|
||||
url, finish := startACMEServerStub(t, man, domain)
|
||||
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), domain)
|
||||
defer finish()
|
||||
|
||||
// use EC key to run faster on 386
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
man.Client = &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: url,
|
||||
}
|
||||
man.Client = &acme.Client{DirectoryURL: url}
|
||||
|
||||
// simulate tls.Config.GetCertificate
|
||||
var tlscert *tls.Certificate
|
||||
var err error
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
tlscert, err = man.GetCertificate(hello)
|
||||
@ -445,13 +604,13 @@ func TestVerifyHTTP01(t *testing.T) {
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK)
|
||||
}
|
||||
if v := string(w.Body.Bytes()); !strings.HasPrefix(v, "token-http-01.") {
|
||||
if v := w.Body.String(); !strings.HasPrefix(v, "token-http-01.") {
|
||||
t.Errorf("http token value = %q; want 'token-http-01.' prefix", v)
|
||||
}
|
||||
}
|
||||
|
||||
// ACME CA server stub, only the needed bits.
|
||||
// TODO: Merge this with startACMEServerStub, making it a configurable CA for testing.
|
||||
// TODO: Replace this with x/crypto/acme/autocert/internal/acmetest.
|
||||
var ca *httptest.Server
|
||||
ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Replay-Nonce", "nonce")
|
||||
@ -505,18 +664,18 @@ func TestVerifyHTTP01(t *testing.T) {
|
||||
}))
|
||||
defer ca.Close()
|
||||
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m := &Manager{
|
||||
Client: &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: ca.URL,
|
||||
},
|
||||
}
|
||||
http01 = m.HTTPHandler(nil)
|
||||
if err := m.verify(context.Background(), m.Client, "example.org"); err != nil {
|
||||
ctx := context.Background()
|
||||
client, err := m.acmeClient(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("m.acmeClient: %v", err)
|
||||
}
|
||||
if err := m.verify(ctx, client, "example.org"); err != nil {
|
||||
t.Errorf("m.verify: %v", err)
|
||||
}
|
||||
// Only tls-sni-01, tls-sni-02 and http-01 must be accepted
|
||||
@ -529,6 +688,111 @@ func TestVerifyHTTP01(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevokeFailedAuthz(t *testing.T) {
|
||||
// Prefill authorization URIs expected to be revoked.
|
||||
// The challenges are selected in a specific order,
|
||||
// each tried within a newly created authorization.
|
||||
// This means each authorization URI corresponds to a different challenge type.
|
||||
revokedAuthz := map[string]bool{
|
||||
"/authz/0": false, // tls-sni-02
|
||||
"/authz/1": false, // tls-sni-01
|
||||
"/authz/2": false, // no viable challenge, but authz is created
|
||||
}
|
||||
|
||||
var authzCount int // num. of created authorizations
|
||||
var revokeCount int // num. of revoked authorizations
|
||||
done := make(chan struct{}) // closed when revokeCount is 3
|
||||
|
||||
// ACME CA server stub, only the needed bits.
|
||||
// TODO: Replace this with x/crypto/acme/autocert/internal/acmetest.
|
||||
var ca *httptest.Server
|
||||
ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Replay-Nonce", "nonce")
|
||||
if r.Method == "HEAD" {
|
||||
// a nonce request
|
||||
return
|
||||
}
|
||||
|
||||
switch r.URL.Path {
|
||||
// Discovery.
|
||||
case "/":
|
||||
if err := discoTmpl.Execute(w, ca.URL); err != nil {
|
||||
t.Errorf("discoTmpl: %v", err)
|
||||
}
|
||||
// Client key registration.
|
||||
case "/new-reg":
|
||||
w.Write([]byte("{}"))
|
||||
// New domain authorization.
|
||||
case "/new-authz":
|
||||
w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount))
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
if err := authzTmpl.Execute(w, ca.URL); err != nil {
|
||||
t.Errorf("authzTmpl: %v", err)
|
||||
}
|
||||
authzCount++
|
||||
// tls-sni-02 challenge "accept" request.
|
||||
case "/challenge/2":
|
||||
// Refuse.
|
||||
http.Error(w, "won't accept tls-sni-02 challenge", http.StatusBadRequest)
|
||||
// tls-sni-01 challenge "accept" request.
|
||||
case "/challenge/1":
|
||||
// Accept but the authorization will be "expired".
|
||||
w.Write([]byte("{}"))
|
||||
// Authorization requests.
|
||||
case "/authz/0", "/authz/1", "/authz/2":
|
||||
// Revocation requests.
|
||||
if r.Method == "POST" {
|
||||
var req struct{ Status string }
|
||||
if err := decodePayload(&req, r.Body); err != nil {
|
||||
t.Errorf("%s: decodePayload: %v", r.URL, err)
|
||||
}
|
||||
switch req.Status {
|
||||
case "deactivated":
|
||||
revokedAuthz[r.URL.Path] = true
|
||||
revokeCount++
|
||||
if revokeCount >= 3 {
|
||||
// Last authorization is revoked.
|
||||
defer close(done)
|
||||
}
|
||||
default:
|
||||
t.Errorf("%s: req.Status = %q; want 'deactivated'", r.URL, req.Status)
|
||||
}
|
||||
w.Write([]byte(`{"status": "invalid"}`))
|
||||
return
|
||||
}
|
||||
// Authorization status requests.
|
||||
// Simulate abandoned authorization, deleted by the CA.
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer ca.Close()
|
||||
|
||||
m := &Manager{
|
||||
Client: &acme.Client{DirectoryURL: ca.URL},
|
||||
}
|
||||
// Should fail and revoke 3 authorizations.
|
||||
// The first 2 are tsl-sni-02 and tls-sni-01 challenges.
|
||||
// The third time an authorization is created but no viable challenge is found.
|
||||
// See revokedAuthz above for more explanation.
|
||||
if _, err := m.createCert(context.Background(), exampleCertKey); err == nil {
|
||||
t.Errorf("m.createCert returned nil error")
|
||||
}
|
||||
select {
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Error("revocations took too long")
|
||||
case <-done:
|
||||
// revokeCount is at least 3.
|
||||
}
|
||||
for uri, ok := range revokedAuthz {
|
||||
if !ok {
|
||||
t.Errorf("%q authorization was not revoked", uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPHandlerDefaultFallback(t *testing.T) {
|
||||
tt := []struct {
|
||||
method, url string
|
||||
@ -571,7 +835,7 @@ func TestHTTPHandlerDefaultFallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAccountKeyCache(t *testing.T) {
|
||||
m := Manager{Cache: newMemCache()}
|
||||
m := Manager{Cache: newMemCache(t)}
|
||||
ctx := context.Background()
|
||||
k1, err := m.accountKey(ctx)
|
||||
if err != nil {
|
||||
@ -587,36 +851,57 @@ func TestAccountKeyCache(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tmpl := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
NotAfter: time.Now().Add(time.Hour),
|
||||
}
|
||||
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey)
|
||||
cert, err := dummyCert(ecdsaKey.Public(), exampleDomain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tlscert := &tls.Certificate{
|
||||
Certificate: [][]byte{pub},
|
||||
PrivateKey: privKey,
|
||||
ecdsaCert := &tls.Certificate{
|
||||
Certificate: [][]byte{cert},
|
||||
PrivateKey: ecdsaKey,
|
||||
}
|
||||
|
||||
man := &Manager{Cache: newMemCache()}
|
||||
rsaKey, err := rsa.GenerateKey(rand.Reader, 512)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cert, err = dummyCert(rsaKey.Public(), exampleDomain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rsaCert := &tls.Certificate{
|
||||
Certificate: [][]byte{cert},
|
||||
PrivateKey: rsaKey,
|
||||
}
|
||||
|
||||
man := &Manager{Cache: newMemCache(t)}
|
||||
defer man.stopRenew()
|
||||
ctx := context.Background()
|
||||
if err := man.cachePut(ctx, "example.org", tlscert); err != nil {
|
||||
|
||||
if err := man.cachePut(ctx, exampleCertKey, ecdsaCert); err != nil {
|
||||
t.Fatalf("man.cachePut: %v", err)
|
||||
}
|
||||
res, err := man.cacheGet(ctx, "example.org")
|
||||
if err := man.cachePut(ctx, exampleCertKeyRSA, rsaCert); err != nil {
|
||||
t.Fatalf("man.cachePut: %v", err)
|
||||
}
|
||||
|
||||
res, err := man.cacheGet(ctx, exampleCertKey)
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
if res == nil {
|
||||
t.Fatal("res is nil")
|
||||
if res == nil || !bytes.Equal(res.Certificate[0], ecdsaCert.Certificate[0]) {
|
||||
t.Errorf("man.cacheGet = %+v; want %+v", res, ecdsaCert)
|
||||
}
|
||||
|
||||
res, err = man.cacheGet(ctx, exampleCertKeyRSA)
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
if res == nil || !bytes.Equal(res.Certificate[0], rsaCert.Certificate[0]) {
|
||||
t.Errorf("man.cacheGet = %+v; want %+v", res, rsaCert)
|
||||
}
|
||||
}
|
||||
|
||||
@ -680,26 +965,28 @@ func TestValidCert(t *testing.T) {
|
||||
}
|
||||
|
||||
tt := []struct {
|
||||
domain string
|
||||
key crypto.Signer
|
||||
cert [][]byte
|
||||
ok bool
|
||||
ck certKey
|
||||
key crypto.Signer
|
||||
cert [][]byte
|
||||
ok bool
|
||||
}{
|
||||
{"example.org", key1, [][]byte{cert1}, true},
|
||||
{"example.org", key3, [][]byte{cert3}, true},
|
||||
{"example.org", key1, [][]byte{cert1, cert2, cert3}, true},
|
||||
{"example.org", key1, [][]byte{cert1, {1}}, false},
|
||||
{"example.org", key1, [][]byte{{1}}, false},
|
||||
{"example.org", key1, [][]byte{cert2}, false},
|
||||
{"example.org", key2, [][]byte{cert1}, false},
|
||||
{"example.org", key1, [][]byte{cert3}, false},
|
||||
{"example.org", key3, [][]byte{cert1}, false},
|
||||
{"example.net", key1, [][]byte{cert1}, false},
|
||||
{"example.org", key1, [][]byte{early}, false},
|
||||
{"example.org", key1, [][]byte{expired}, false},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{cert1}, true},
|
||||
{certKey{domain: "example.org", isRSA: true}, key3, [][]byte{cert3}, true},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{cert1, cert2, cert3}, true},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{cert1, {1}}, false},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{{1}}, false},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{cert2}, false},
|
||||
{certKey{domain: "example.org"}, key2, [][]byte{cert1}, false},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{cert3}, false},
|
||||
{certKey{domain: "example.org"}, key3, [][]byte{cert1}, false},
|
||||
{certKey{domain: "example.net"}, key1, [][]byte{cert1}, false},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{early}, false},
|
||||
{certKey{domain: "example.org"}, key1, [][]byte{expired}, false},
|
||||
{certKey{domain: "example.org", isRSA: true}, key1, [][]byte{cert1}, false},
|
||||
{certKey{domain: "example.org"}, key3, [][]byte{cert3}, false},
|
||||
}
|
||||
for i, test := range tt {
|
||||
leaf, err := validCert(test.domain, test.cert, test.key)
|
||||
leaf, err := validCert(test.ck, test.cert, test.key, now)
|
||||
if err != nil && test.ok {
|
||||
t.Errorf("%d: err = %v", i, err)
|
||||
}
|
||||
@ -748,10 +1035,155 @@ func TestManagerGetCertificateBogusSNI(t *testing.T) {
|
||||
{"fo.o", "cache.Get of fo.o"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
_, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name})
|
||||
_, err := m.GetCertificate(clientHelloInfo(tt.name, true))
|
||||
got := fmt.Sprint(err)
|
||||
if got != tt.wantErr {
|
||||
t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertRequest(t *testing.T) {
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// An extension from RFC7633. Any will do.
|
||||
ext := pkix.Extension{
|
||||
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1},
|
||||
Value: []byte("dummy"),
|
||||
}
|
||||
b, err := certRequest(key, "example.org", []pkix.Extension{ext}, "san.example.org")
|
||||
if err != nil {
|
||||
t.Fatalf("certRequest: %v", err)
|
||||
}
|
||||
r, err := x509.ParseCertificateRequest(b)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseCertificateRequest: %v", err)
|
||||
}
|
||||
var found bool
|
||||
for _, v := range r.Extensions {
|
||||
if v.Id.Equal(ext.Id) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("want %v in Extensions: %v", ext, r.Extensions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSupportsECDSA(t *testing.T) {
|
||||
tests := []struct {
|
||||
CipherSuites []uint16
|
||||
SignatureSchemes []tls.SignatureScheme
|
||||
SupportedCurves []tls.CurveID
|
||||
ecdsaOk bool
|
||||
}{
|
||||
{[]uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
}, nil, nil, false},
|
||||
{[]uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
}, nil, nil, true},
|
||||
|
||||
// SignatureSchemes limits, not extends, CipherSuites
|
||||
{[]uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
}, []tls.SignatureScheme{
|
||||
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
|
||||
}, nil, false},
|
||||
{[]uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
}, []tls.SignatureScheme{
|
||||
tls.PKCS1WithSHA256,
|
||||
}, nil, false},
|
||||
{[]uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
}, []tls.SignatureScheme{
|
||||
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
|
||||
}, nil, true},
|
||||
|
||||
{[]uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
}, []tls.SignatureScheme{
|
||||
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
|
||||
}, []tls.CurveID{
|
||||
tls.CurveP521,
|
||||
}, false},
|
||||
{[]uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
}, []tls.SignatureScheme{
|
||||
tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256,
|
||||
}, []tls.CurveID{
|
||||
tls.CurveP256,
|
||||
tls.CurveP521,
|
||||
}, true},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
result := supportsECDSA(&tls.ClientHelloInfo{
|
||||
CipherSuites: tt.CipherSuites,
|
||||
SignatureSchemes: tt.SignatureSchemes,
|
||||
SupportedCurves: tt.SupportedCurves,
|
||||
})
|
||||
if result != tt.ecdsaOk {
|
||||
t.Errorf("%d: supportsECDSA = %v; want %v", i, result, tt.ecdsaOk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add same end-to-end for http-01 challenge type.
|
||||
func TestEndToEnd(t *testing.T) {
|
||||
const domain = "example.org"
|
||||
|
||||
// ACME CA server
|
||||
ca := acmetest.NewCAServer([]string{"tls-alpn-01"}, []string{domain})
|
||||
defer ca.Close()
|
||||
|
||||
// User dummy server.
|
||||
m := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Client: &acme.Client{DirectoryURL: ca.URL},
|
||||
}
|
||||
us := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("OK"))
|
||||
}))
|
||||
us.TLS = &tls.Config{
|
||||
NextProtos: []string{"http/1.1", acme.ALPNProto},
|
||||
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
cert, err := m.GetCertificate(hello)
|
||||
if err != nil {
|
||||
t.Errorf("m.GetCertificate: %v", err)
|
||||
}
|
||||
return cert, err
|
||||
},
|
||||
}
|
||||
us.StartTLS()
|
||||
defer us.Close()
|
||||
// In TLS-ALPN challenge verification, CA connects to the domain:443 in question.
|
||||
// Because the domain won't resolve in tests, we need to tell the CA
|
||||
// where to dial to instead.
|
||||
ca.Resolve(domain, strings.TrimPrefix(us.URL, "https://"))
|
||||
|
||||
// A client visiting user dummy server.
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: ca.Roots,
|
||||
ServerName: domain,
|
||||
},
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
res, err := client.Get(us.URL)
|
||||
if err != nil {
|
||||
t.Logf("CA errors: %v", ca.Errors())
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
b, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v := string(b); v != "OK" {
|
||||
t.Errorf("user server response: %q; want 'OK'", v)
|
||||
}
|
||||
}
|
||||
|
6
vendor/golang.org/x/crypto/acme/autocert/cache.go
generated
vendored
6
vendor/golang.org/x/crypto/acme/autocert/cache.go
generated
vendored
@ -16,10 +16,10 @@ import (
|
||||
var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss")
|
||||
|
||||
// Cache is used by Manager to store and retrieve previously obtained certificates
|
||||
// as opaque data.
|
||||
// and other account data as opaque blobs.
|
||||
//
|
||||
// The key argument of the methods refers to a domain name but need not be an FQDN.
|
||||
// Cache implementations should not rely on the key naming pattern.
|
||||
// Cache implementations should not rely on the key naming pattern. Keys can
|
||||
// include any printable ASCII characters, except the following: \/:*?"<>|
|
||||
type Cache interface {
|
||||
// Get returns a certificate data for the specified key.
|
||||
// If there's no such key, Get returns ErrCacheMiss.
|
||||
|
6
vendor/golang.org/x/crypto/acme/autocert/example_test.go
generated
vendored
6
vendor/golang.org/x/crypto/acme/autocert/example_test.go
generated
vendored
@ -5,7 +5,6 @@
|
||||
package autocert_test
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -25,12 +24,11 @@ func ExampleManager() {
|
||||
m := &autocert.Manager{
|
||||
Cache: autocert.DirCache("secret-dir"),
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist("example.org"),
|
||||
HostPolicy: autocert.HostWhitelist("example.org", "www.example.org"),
|
||||
}
|
||||
go http.ListenAndServe(":http", m.HTTPHandler(nil))
|
||||
s := &http.Server{
|
||||
Addr: ":https",
|
||||
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
|
||||
TLSConfig: m.TLSConfig(),
|
||||
}
|
||||
s.ListenAndServeTLS("", "")
|
||||
}
|
||||
|
7
vendor/golang.org/x/crypto/acme/autocert/listener.go
generated
vendored
7
vendor/golang.org/x/crypto/acme/autocert/listener.go
generated
vendored
@ -72,11 +72,8 @@ func NewListener(domains ...string) net.Listener {
|
||||
// the Manager m's Prompt, Cache, HostPolicy, and other desired options.
|
||||
func (m *Manager) Listener() net.Listener {
|
||||
ln := &listener{
|
||||
m: m,
|
||||
conf: &tls.Config{
|
||||
GetCertificate: m.GetCertificate, // bonus: panic on nil m
|
||||
NextProtos: []string{"h2", "http/1.1"}, // Enable HTTP/2
|
||||
},
|
||||
m: m,
|
||||
conf: m.TLSConfig(),
|
||||
}
|
||||
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
|
||||
return ln
|
||||
|
45
vendor/golang.org/x/crypto/acme/autocert/renewal.go
generated
vendored
45
vendor/golang.org/x/crypto/acme/autocert/renewal.go
generated
vendored
@ -17,9 +17,9 @@ const renewJitter = time.Hour
|
||||
// domainRenewal tracks the state used by the periodic timers
|
||||
// renewing a single domain's cert.
|
||||
type domainRenewal struct {
|
||||
m *Manager
|
||||
domain string
|
||||
key crypto.Signer
|
||||
m *Manager
|
||||
ck certKey
|
||||
key crypto.Signer
|
||||
|
||||
timerMu sync.Mutex
|
||||
timer *time.Timer
|
||||
@ -71,25 +71,43 @@ func (dr *domainRenewal) renew() {
|
||||
testDidRenewLoop(next, err)
|
||||
}
|
||||
|
||||
// updateState locks and replaces the relevant Manager.state item with the given
|
||||
// state. It additionally updates dr.key with the given state's key.
|
||||
func (dr *domainRenewal) updateState(state *certState) {
|
||||
dr.m.stateMu.Lock()
|
||||
defer dr.m.stateMu.Unlock()
|
||||
dr.key = state.key
|
||||
dr.m.state[dr.ck] = state
|
||||
}
|
||||
|
||||
// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
|
||||
// Instead, it requests a new certificate independently and, upon success,
|
||||
// replaces dr.m.state item with a new one and updates cache for the given domain.
|
||||
//
|
||||
// It may return immediately if the expiration date of the currently cached cert
|
||||
// is far enough in the future.
|
||||
// It may lock and update the Manager.state if the expiration date of the currently
|
||||
// cached cert is far enough in the future.
|
||||
//
|
||||
// The returned value is a time interval after which the renewal should occur again.
|
||||
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
||||
// a race is likely unavoidable in a distributed environment
|
||||
// but we try nonetheless
|
||||
if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil {
|
||||
if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil {
|
||||
next := dr.next(tlscert.Leaf.NotAfter)
|
||||
if next > dr.m.renewBefore()+renewJitter {
|
||||
return next, nil
|
||||
signer, ok := tlscert.PrivateKey.(crypto.Signer)
|
||||
if ok {
|
||||
state := &certState{
|
||||
key: signer,
|
||||
cert: tlscert.Certificate,
|
||||
leaf: tlscert.Leaf,
|
||||
}
|
||||
dr.updateState(state)
|
||||
return next, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain)
|
||||
der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -102,16 +120,15 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dr.m.cachePut(ctx, dr.domain, tlscert)
|
||||
dr.m.stateMu.Lock()
|
||||
defer dr.m.stateMu.Unlock()
|
||||
// m.state is guaranteed to be non-nil at this point
|
||||
dr.m.state[dr.domain] = state
|
||||
if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dr.updateState(state)
|
||||
return dr.next(leaf.NotAfter), nil
|
||||
}
|
||||
|
||||
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
|
||||
d := expiry.Sub(timeNow()) - dr.m.renewBefore()
|
||||
d := expiry.Sub(dr.m.now()) - dr.m.renewBefore()
|
||||
// add a bit of randomness to renew deadline
|
||||
n := pseudoRand.int63n(int64(renewJitter))
|
||||
d -= time.Duration(n)
|
||||
|
178
vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
generated
vendored
178
vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
generated
vendored
@ -23,10 +23,10 @@ import (
|
||||
|
||||
func TestRenewalNext(t *testing.T) {
|
||||
now := time.Now()
|
||||
timeNow = func() time.Time { return now }
|
||||
defer func() { timeNow = time.Now }()
|
||||
|
||||
man := &Manager{RenewBefore: 7 * 24 * time.Hour}
|
||||
man := &Manager{
|
||||
RenewBefore: 7 * 24 * time.Hour,
|
||||
nowFunc: func() time.Time { return now },
|
||||
}
|
||||
defer man.stopRenew()
|
||||
tt := []struct {
|
||||
expiry time.Time
|
||||
@ -48,8 +48,6 @@ func TestRenewalNext(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenewFromCache(t *testing.T) {
|
||||
const domain = "example.org"
|
||||
|
||||
// ACME CA server stub
|
||||
var ca *httptest.Server
|
||||
ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@ -84,7 +82,7 @@ func TestRenewFromCache(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("new-cert: CSR: %v", err)
|
||||
}
|
||||
der, err := dummyCert(csr.PublicKey, domain)
|
||||
der, err := dummyCert(csr.PublicKey, exampleDomain)
|
||||
if err != nil {
|
||||
t.Fatalf("new-cert: dummyCert: %v", err)
|
||||
}
|
||||
@ -105,30 +103,28 @@ func TestRenewFromCache(t *testing.T) {
|
||||
}))
|
||||
defer ca.Close()
|
||||
|
||||
// use EC key to run faster on 386
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: newMemCache(),
|
||||
Cache: newMemCache(t),
|
||||
RenewBefore: 24 * time.Hour,
|
||||
Client: &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: ca.URL,
|
||||
},
|
||||
}
|
||||
defer man.stopRenew()
|
||||
|
||||
// cache an almost expired cert
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
now := time.Now()
|
||||
cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain)
|
||||
cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
|
||||
if err := man.cachePut(context.Background(), domain, tlscert); err != nil {
|
||||
if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -152,7 +148,7 @@ func TestRenewFromCache(t *testing.T) {
|
||||
|
||||
// ensure the new cert is cached
|
||||
after := time.Now().Add(future)
|
||||
tlscert, err := man.cacheGet(context.Background(), domain)
|
||||
tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
@ -163,9 +159,9 @@ func TestRenewFromCache(t *testing.T) {
|
||||
// verify the old cert is also replaced in memory
|
||||
man.stateMu.Lock()
|
||||
defer man.stateMu.Unlock()
|
||||
s := man.state[domain]
|
||||
s := man.state[exampleCertKey]
|
||||
if s == nil {
|
||||
t.Fatalf("m.state[%q] is nil", domain)
|
||||
t.Fatalf("m.state[%q] is nil", exampleCertKey)
|
||||
}
|
||||
tlscert, err = s.tlscert()
|
||||
if err != nil {
|
||||
@ -177,7 +173,7 @@ func TestRenewFromCache(t *testing.T) {
|
||||
}
|
||||
|
||||
// trigger renew
|
||||
hello := &tls.ClientHelloInfo{ServerName: domain}
|
||||
hello := clientHelloInfo(exampleDomain, true)
|
||||
if _, err := man.GetCertificate(hello); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -189,3 +185,145 @@ func TestRenewFromCache(t *testing.T) {
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: newMemCache(t),
|
||||
RenewBefore: 24 * time.Hour,
|
||||
Client: &acme.Client{
|
||||
DirectoryURL: "invalid",
|
||||
},
|
||||
}
|
||||
defer man.stopRenew()
|
||||
|
||||
// cache a recently renewed cert with a different private key
|
||||
newKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
now := time.Now()
|
||||
newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), exampleDomain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newLeaf, err := validCert(exampleCertKey, [][]byte{newCert}, newKey, now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newTLSCert := &tls.Certificate{PrivateKey: newKey, Certificate: [][]byte{newCert}, Leaf: newLeaf}
|
||||
if err := man.cachePut(context.Background(), exampleCertKey, newTLSCert); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// set internal state to an almost expired cert
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
oldLeaf, err := validCert(exampleCertKey, [][]byte{oldCert}, key, now)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
man.stateMu.Lock()
|
||||
if man.state == nil {
|
||||
man.state = make(map[certKey]*certState)
|
||||
}
|
||||
s := &certState{
|
||||
key: key,
|
||||
cert: [][]byte{oldCert},
|
||||
leaf: oldLeaf,
|
||||
}
|
||||
man.state[exampleCertKey] = s
|
||||
man.stateMu.Unlock()
|
||||
|
||||
// veriy the renewal accepted the newer cached cert
|
||||
defer func() {
|
||||
testDidRenewLoop = func(next time.Duration, err error) {}
|
||||
}()
|
||||
done := make(chan struct{})
|
||||
testDidRenewLoop = func(next time.Duration, err error) {
|
||||
defer close(done)
|
||||
if err != nil {
|
||||
t.Errorf("testDidRenewLoop: %v", err)
|
||||
}
|
||||
// Next should be about 90 days
|
||||
// Previous expiration was within 1 min.
|
||||
future := 88 * 24 * time.Hour
|
||||
if next < future {
|
||||
t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future)
|
||||
}
|
||||
|
||||
// ensure the cached cert was not modified
|
||||
tlscert, err := man.cacheGet(context.Background(), exampleCertKey)
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) {
|
||||
t.Errorf("cache leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter)
|
||||
}
|
||||
|
||||
// verify the old cert is also replaced in memory
|
||||
man.stateMu.Lock()
|
||||
defer man.stateMu.Unlock()
|
||||
s := man.state[exampleCertKey]
|
||||
if s == nil {
|
||||
t.Fatalf("m.state[%q] is nil", exampleCertKey)
|
||||
}
|
||||
stateKey := s.key.Public().(*ecdsa.PublicKey)
|
||||
if stateKey.X.Cmp(newKey.X) != 0 || stateKey.Y.Cmp(newKey.Y) != 0 {
|
||||
t.Fatalf("state key was not updated from cache x: %v y: %v; want x: %v y: %v", stateKey.X, stateKey.Y, newKey.X, newKey.Y)
|
||||
}
|
||||
tlscert, err = s.tlscert()
|
||||
if err != nil {
|
||||
t.Fatalf("s.tlscert: %v", err)
|
||||
}
|
||||
if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) {
|
||||
t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter)
|
||||
}
|
||||
|
||||
// verify the private key is replaced in the renewal state
|
||||
r := man.renewal[exampleCertKey]
|
||||
if r == nil {
|
||||
t.Fatalf("m.renewal[%q] is nil", exampleCertKey)
|
||||
}
|
||||
renewalKey := r.key.Public().(*ecdsa.PublicKey)
|
||||
if renewalKey.X.Cmp(newKey.X) != 0 || renewalKey.Y.Cmp(newKey.Y) != 0 {
|
||||
t.Fatalf("renewal private key was not updated from cache x: %v y: %v; want x: %v y: %v", renewalKey.X, renewalKey.Y, newKey.X, newKey.Y)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// assert the expiring cert is returned from state
|
||||
hello := clientHelloInfo(exampleDomain, true)
|
||||
tlscert, err := man.GetCertificate(hello)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !oldLeaf.NotAfter.Equal(tlscert.Leaf.NotAfter) {
|
||||
t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, oldLeaf.NotAfter)
|
||||
}
|
||||
|
||||
// trigger renew
|
||||
go man.renew(exampleCertKey, s.key, s.leaf.NotAfter)
|
||||
|
||||
// wait for renew loop
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("renew took too long to occur")
|
||||
case <-done:
|
||||
// assert the new cert is returned from state after renew
|
||||
hello := clientHelloInfo(exampleDomain, true)
|
||||
tlscert, err := man.GetCertificate(hello)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !newTLSCert.Leaf.NotAfter.Equal(tlscert.Leaf.NotAfter) {
|
||||
t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newTLSCert.Leaf.NotAfter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
vendor/golang.org/x/crypto/acme/jws.go
generated
vendored
29
vendor/golang.org/x/crypto/acme/jws.go
generated
vendored
@ -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":
|
||||
|
75
vendor/golang.org/x/crypto/acme/jws_test.go
generated
vendored
75
vendor/golang.org/x/crypto/acme/jws_test.go
generated
vendored
@ -5,6 +5,7 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
@ -13,6 +14,7 @@ import (
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
@ -241,6 +243,79 @@ func TestJWSEncodeJSONEC(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type customTestSigner struct {
|
||||
sig []byte
|
||||
pub crypto.PublicKey
|
||||
}
|
||||
|
||||
func (s *customTestSigner) Public() crypto.PublicKey { return s.pub }
|
||||
func (s *customTestSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) {
|
||||
return s.sig, nil
|
||||
}
|
||||
|
||||
func TestJWSEncodeJSONCustom(t *testing.T) {
|
||||
claims := struct{ Msg string }{"hello"}
|
||||
const (
|
||||
// printf '{"Msg":"hello"}' | base64 | tr -d '=' | tr '/+' '_-'
|
||||
payload = "eyJNc2ciOiJoZWxsbyJ9"
|
||||
// printf 'testsig' | base64 | tr -d '='
|
||||
testsig = "dGVzdHNpZw"
|
||||
|
||||
// printf '{"alg":"ES256","jwk":{"crv":"P-256","kty":"EC","x":<testKeyECPubY>,"y":<testKeyECPubY>,"nonce":"nonce"}' | \
|
||||
// base64 | tr -d '=' | tr '/+' '_-'
|
||||
es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjVsaEV1" +
|
||||
"ZzV4SzR4QkRaMm5BYmF4THRhTGl2ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFH" +
|
||||
"a3YwVGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6Im5vbmNlIn0"
|
||||
|
||||
// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
|
||||
rs256phead = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
|
||||
"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
|
||||
"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
|
||||
"QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
|
||||
"VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
|
||||
"NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
|
||||
"QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
|
||||
"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
|
||||
"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
|
||||
"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
|
||||
"UVEifSwibm9uY2UiOiJub25jZSJ9"
|
||||
)
|
||||
|
||||
tt := []struct {
|
||||
alg, phead string
|
||||
pub crypto.PublicKey
|
||||
}{
|
||||
{"RS256", rs256phead, testKey.Public()},
|
||||
{"ES256", es256phead, testKeyEC.Public()},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
tc := tc
|
||||
t.Run(tc.alg, func(t *testing.T) {
|
||||
signer := &customTestSigner{
|
||||
sig: []byte("testsig"),
|
||||
pub: tc.pub,
|
||||
}
|
||||
b, err := jwsEncodeJSON(claims, signer, "nonce")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var j struct{ Protected, Payload, Signature string }
|
||||
if err := json.Unmarshal(b, &j); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if j.Protected != tc.phead {
|
||||
t.Errorf("j.Protected = %q\nwant %q", j.Protected, tc.phead)
|
||||
}
|
||||
if j.Payload != payload {
|
||||
t.Errorf("j.Payload = %q\nwant %q", j.Payload, payload)
|
||||
}
|
||||
if j.Signature != testsig {
|
||||
t.Errorf("j.Signature = %q\nwant %q", j.Signature, testsig)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJWKThumbprintRSA(t *testing.T) {
|
||||
// Key example from RFC 7638
|
||||
const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" +
|
||||
|
8
vendor/golang.org/x/crypto/acme/types.go
generated
vendored
8
vendor/golang.org/x/crypto/acme/types.go
generated
vendored
@ -104,7 +104,7 @@ func RateLimit(err error) (time.Duration, bool) {
|
||||
if e.Header == nil {
|
||||
return 0, true
|
||||
}
|
||||
return retryAfter(e.Header.Get("Retry-After"), 0), true
|
||||
return retryAfter(e.Header.Get("Retry-After")), true
|
||||
}
|
||||
|
||||
// Account is a user account. It is associated with a private key.
|
||||
@ -296,8 +296,8 @@ func (e *wireError) error(h http.Header) *Error {
|
||||
}
|
||||
}
|
||||
|
||||
// CertOption is an optional argument type for the TLSSNIxChallengeCert methods for
|
||||
// customizing a temporary certificate for TLS-SNI challenges.
|
||||
// CertOption is an optional argument type for the TLS ChallengeCert methods for
|
||||
// customizing a temporary certificate for TLS-based challenges.
|
||||
type CertOption interface {
|
||||
privateCertOpt()
|
||||
}
|
||||
@ -317,7 +317,7 @@ func (*certOptKey) privateCertOpt() {}
|
||||
// WithTemplate creates an option for specifying a certificate template.
|
||||
// See x509.CreateCertificate for template usage details.
|
||||
//
|
||||
// In TLSSNIxChallengeCert methods, the template is also used as parent,
|
||||
// In TLS ChallengeCert methods, the template is also used as parent,
|
||||
// resulting in a self-signed certificate.
|
||||
// The DNSNames field of t is always overwritten for tls-sni challenge certs.
|
||||
func WithTemplate(t *x509.Certificate) CertOption {
|
||||
|
81
vendor/golang.org/x/crypto/argon2/argon2.go
generated
vendored
81
vendor/golang.org/x/crypto/argon2/argon2.go
generated
vendored
@ -5,7 +5,35 @@
|
||||
// Package argon2 implements the key derivation function Argon2.
|
||||
// Argon2 was selected as the winner of the Password Hashing Competition and can
|
||||
// be used to derive cryptographic keys from passwords.
|
||||
// Argon2 is specfifed at https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
|
||||
//
|
||||
// For a detailed specification of Argon2 see [1].
|
||||
//
|
||||
// If you aren't sure which function you need, use Argon2id (IDKey) and
|
||||
// the parameter recommendations for your scenario.
|
||||
//
|
||||
//
|
||||
// Argon2i
|
||||
//
|
||||
// Argon2i (implemented by Key) is the side-channel resistant version of Argon2.
|
||||
// It uses data-independent memory access, which is preferred for password
|
||||
// hashing and password-based key derivation. Argon2i requires more passes over
|
||||
// memory than Argon2id to protect from trade-off attacks. The recommended
|
||||
// parameters (taken from [2]) for non-interactive operations are time=3 and to
|
||||
// use the maximum available memory.
|
||||
//
|
||||
//
|
||||
// Argon2id
|
||||
//
|
||||
// Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining
|
||||
// Argon2i and Argon2d. It uses data-independent memory access for the first
|
||||
// half of the first iteration over the memory and data-dependent memory access
|
||||
// for the rest. Argon2id is side-channel resistant and provides better brute-
|
||||
// force cost savings due to time-memory tradeoffs than Argon2i. The recommended
|
||||
// parameters for non-interactive operations (taken from [2]) are time=1 and to
|
||||
// use the maximum available memory.
|
||||
//
|
||||
// [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
|
||||
// [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3
|
||||
package argon2
|
||||
|
||||
import (
|
||||
@ -25,23 +53,52 @@ const (
|
||||
)
|
||||
|
||||
// Key derives a key from the password, salt, and cost parameters using Argon2i
|
||||
// returning a byte slice of length keyLen that can be used as cryptographic key.
|
||||
// The CPU cost and parallism degree must be greater than zero.
|
||||
// returning a byte slice of length keyLen that can be used as cryptographic
|
||||
// key. The CPU cost and parallelism degree must be greater than zero.
|
||||
//
|
||||
// For example, you can get a derived key for e.g. AES-256 (which needs a 32-byte key) by doing:
|
||||
// `key := argon2.Key([]byte("some password"), salt, 4, 32*1024, 4, 32)`
|
||||
// For example, you can get a derived key for e.g. AES-256 (which needs a
|
||||
// 32-byte key) by doing:
|
||||
//
|
||||
// The recommended parameters for interactive logins as of 2017 are time=4, memory=32*1024.
|
||||
// The number of threads can be adjusted to the numbers of available CPUs.
|
||||
// The time parameter specifies the number of passes over the memory and the memory
|
||||
// parameter specifies the size of the memory in KiB. For example memory=32*1024 sets the
|
||||
// memory cost to ~32 MB.
|
||||
// The cost parameters should be increased as memory latency and CPU parallelism increases.
|
||||
// Remember to get a good random salt.
|
||||
// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32)
|
||||
//
|
||||
// The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number.
|
||||
// If using that amount of memory (32 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
//
|
||||
// The time parameter specifies the number of passes over the memory and the
|
||||
// memory parameter specifies the size of the memory in KiB. For example
|
||||
// memory=32*1024 sets the memory cost to ~32 MB. The number of threads can be
|
||||
// adjusted to the number of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
|
||||
// IDKey derives a key from the password, salt, and cost parameters using
|
||||
// Argon2id returning a byte slice of length keyLen that can be used as
|
||||
// cryptographic key. The CPU cost and parallelism degree must be greater than
|
||||
// zero.
|
||||
//
|
||||
// For example, you can get a derived key for e.g. AES-256 (which needs a
|
||||
// 32-byte key) by doing:
|
||||
//
|
||||
// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32)
|
||||
//
|
||||
// The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number.
|
||||
// If using that amount of memory (64 MB) is not possible in some contexts then
|
||||
// the time parameter can be increased to compensate.
|
||||
//
|
||||
// The time parameter specifies the number of passes over the memory and the
|
||||
// memory parameter specifies the size of the memory in KiB. For example
|
||||
// memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be
|
||||
// adjusted to the numbers of available CPUs. The cost parameters should be
|
||||
// increased as memory latency and CPU parallelism increases. Remember to get a
|
||||
// good random salt.
|
||||
func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
|
||||
}
|
||||
|
||||
func deriveKey(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
|
||||
if time < 1 {
|
||||
panic("argon2: number of rounds too small")
|
||||
|
9
vendor/golang.org/x/crypto/argon2/blamka_amd64.go
generated
vendored
9
vendor/golang.org/x/crypto/argon2/blamka_amd64.go
generated
vendored
@ -6,12 +6,11 @@
|
||||
|
||||
package argon2
|
||||
|
||||
func init() {
|
||||
useSSE4 = supportsSSE4()
|
||||
}
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
//go:noescape
|
||||
func supportsSSE4() bool
|
||||
func init() {
|
||||
useSSE4 = cpu.X86.HasSSE41
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func mixBlocksSSE2(out, a, b, c *block)
|
||||
|
9
vendor/golang.org/x/crypto/argon2/blamka_amd64.s
generated
vendored
9
vendor/golang.org/x/crypto/argon2/blamka_amd64.s
generated
vendored
@ -241,12 +241,3 @@ loop:
|
||||
SUBQ $2, BP
|
||||
JA loop
|
||||
RET
|
||||
|
||||
// func supportsSSE4() bool
|
||||
TEXT ·supportsSSE4(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
SHRL $19, CX // Bit 19 indicates SSE4 support
|
||||
ANDL $1, CX // CX != 0 if support SSE4
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
||||
|
6
vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
generated
vendored
6
vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
generated
vendored
@ -209,19 +209,19 @@ func TestMinorNotRequired(t *testing.T) {
|
||||
func BenchmarkEqual(b *testing.B) {
|
||||
b.StopTimer()
|
||||
passwd := []byte("somepasswordyoulike")
|
||||
hash, _ := GenerateFromPassword(passwd, 10)
|
||||
hash, _ := GenerateFromPassword(passwd, DefaultCost)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
CompareHashAndPassword(hash, passwd)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGeneration(b *testing.B) {
|
||||
func BenchmarkDefaultCost(b *testing.B) {
|
||||
b.StopTimer()
|
||||
passwd := []byte("mylongpassword1234")
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
GenerateFromPassword(passwd, 10)
|
||||
GenerateFromPassword(passwd, DefaultCost)
|
||||
}
|
||||
}
|
||||
|
||||
|
76
vendor/golang.org/x/crypto/blake2b/blake2b.go
generated
vendored
76
vendor/golang.org/x/crypto/blake2b/blake2b.go
generated
vendored
@ -75,23 +75,25 @@ func Sum256(data []byte) [Size256]byte {
|
||||
}
|
||||
|
||||
// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
|
||||
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
|
||||
func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
||||
|
||||
// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
|
||||
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
|
||||
func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
|
||||
|
||||
// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
|
||||
// key turns the hash into a MAC. The key must be between zero and 64 bytes long.
|
||||
func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
|
||||
|
||||
// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
|
||||
// A non-nil key turns the hash into a MAC. The key must between zero and 64 bytes long.
|
||||
// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long.
|
||||
// The hash size can be a value between 1 and 64 but it is highly recommended to use
|
||||
// values equal or greater than:
|
||||
// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).
|
||||
// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long).
|
||||
// When the key is nil, the returned hash.Hash implements BinaryMarshaler
|
||||
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
|
||||
func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) }
|
||||
|
||||
func newDigest(hashSize int, key []byte) (*digest, error) {
|
||||
@ -150,6 +152,50 @@ type digest struct {
|
||||
keyLen int
|
||||
}
|
||||
|
||||
const (
|
||||
magic = "b2b"
|
||||
marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1
|
||||
)
|
||||
|
||||
func (d *digest) MarshalBinary() ([]byte, error) {
|
||||
if d.keyLen != 0 {
|
||||
return nil, errors.New("crypto/blake2b: cannot marshal MACs")
|
||||
}
|
||||
b := make([]byte, 0, marshaledSize)
|
||||
b = append(b, magic...)
|
||||
for i := 0; i < 8; i++ {
|
||||
b = appendUint64(b, d.h[i])
|
||||
}
|
||||
b = appendUint64(b, d.c[0])
|
||||
b = appendUint64(b, d.c[1])
|
||||
// Maximum value for size is 64
|
||||
b = append(b, byte(d.size))
|
||||
b = append(b, d.block[:]...)
|
||||
b = append(b, byte(d.offset))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (d *digest) UnmarshalBinary(b []byte) error {
|
||||
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
|
||||
return errors.New("crypto/blake2b: invalid hash state identifier")
|
||||
}
|
||||
if len(b) != marshaledSize {
|
||||
return errors.New("crypto/blake2b: invalid hash state size")
|
||||
}
|
||||
b = b[len(magic):]
|
||||
for i := 0; i < 8; i++ {
|
||||
b, d.h[i] = consumeUint64(b)
|
||||
}
|
||||
b, d.c[0] = consumeUint64(b)
|
||||
b, d.c[1] = consumeUint64(b)
|
||||
d.size = int(b[0])
|
||||
b = b[1:]
|
||||
copy(d.block[:], b[:BlockSize])
|
||||
b = b[BlockSize:]
|
||||
d.offset = int(b[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Size() int { return d.size }
|
||||
@ -219,3 +265,25 @@ func (d *digest) finalize(hash *[Size]byte) {
|
||||
binary.LittleEndian.PutUint64(hash[8*i:], v)
|
||||
}
|
||||
}
|
||||
|
||||
func appendUint64(b []byte, x uint64) []byte {
|
||||
var a [8]byte
|
||||
binary.BigEndian.PutUint64(a[:], x)
|
||||
return append(b, a[:]...)
|
||||
}
|
||||
|
||||
func appendUint32(b []byte, x uint32) []byte {
|
||||
var a [4]byte
|
||||
binary.BigEndian.PutUint32(a[:], x)
|
||||
return append(b, a[:]...)
|
||||
}
|
||||
|
||||
func consumeUint64(b []byte) ([]byte, uint64) {
|
||||
x := binary.BigEndian.Uint64(b)
|
||||
return b[8:], x
|
||||
}
|
||||
|
||||
func consumeUint32(b []byte) ([]byte, uint32) {
|
||||
x := binary.BigEndian.Uint32(b)
|
||||
return b[4:], x
|
||||
}
|
||||
|
26
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go
generated
vendored
26
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go
generated
vendored
@ -6,21 +6,14 @@
|
||||
|
||||
package blake2b
|
||||
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
func init() {
|
||||
useAVX2 = supportsAVX2()
|
||||
useAVX = supportsAVX()
|
||||
useSSE4 = supportsSSE4()
|
||||
useAVX2 = cpu.X86.HasAVX2
|
||||
useAVX = cpu.X86.HasAVX
|
||||
useSSE4 = cpu.X86.HasSSE41
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func supportsSSE4() bool
|
||||
|
||||
//go:noescape
|
||||
func supportsAVX() bool
|
||||
|
||||
//go:noescape
|
||||
func supportsAVX2() bool
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
|
||||
@ -31,13 +24,14 @@ func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
|
||||
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
|
||||
if useAVX2 {
|
||||
switch {
|
||||
case useAVX2:
|
||||
hashBlocksAVX2(h, c, flag, blocks)
|
||||
} else if useAVX {
|
||||
case useAVX:
|
||||
hashBlocksAVX(h, c, flag, blocks)
|
||||
} else if useSSE4 {
|
||||
case useSSE4:
|
||||
hashBlocksSSE4(h, c, flag, blocks)
|
||||
} else {
|
||||
default:
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
||||
}
|
||||
|
12
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
generated
vendored
12
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
generated
vendored
@ -748,15 +748,3 @@ noinc:
|
||||
|
||||
MOVQ BP, SP
|
||||
RET
|
||||
|
||||
// func supportsAVX2() bool
|
||||
TEXT ·supportsAVX2(SB), 4, $0-1
|
||||
MOVQ runtime·support_avx2(SB), AX
|
||||
MOVB AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func supportsAVX() bool
|
||||
TEXT ·supportsAVX(SB), 4, $0-1
|
||||
MOVQ runtime·support_avx(SB), AX
|
||||
MOVB AX, ret+0(FP)
|
||||
RET
|
||||
|
9
vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go
generated
vendored
9
vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go
generated
vendored
@ -6,12 +6,11 @@
|
||||
|
||||
package blake2b
|
||||
|
||||
func init() {
|
||||
useSSE4 = supportsSSE4()
|
||||
}
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
//go:noescape
|
||||
func supportsSSE4() bool
|
||||
func init() {
|
||||
useSSE4 = cpu.X86.HasSSE41
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
|
9
vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s
generated
vendored
9
vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s
generated
vendored
@ -279,12 +279,3 @@ noinc:
|
||||
|
||||
MOVQ BP, SP
|
||||
RET
|
||||
|
||||
// func supportsSSE4() bool
|
||||
TEXT ·supportsSSE4(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
SHRL $19, CX // Bit 19 indicates SSE4 support
|
||||
ANDL $1, CX // CX != 0 if support SSE4
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
||||
|
49
vendor/golang.org/x/crypto/blake2b/blake2b_test.go
generated
vendored
49
vendor/golang.org/x/crypto/blake2b/blake2b_test.go
generated
vendored
@ -6,6 +6,7 @@ package blake2b
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
@ -69,6 +70,54 @@ func TestHashes2X(t *testing.T) {
|
||||
testHashes2X(t)
|
||||
}
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
input := make([]byte, 255)
|
||||
for i := range input {
|
||||
input[i] = byte(i)
|
||||
}
|
||||
for _, size := range []int{Size, Size256, Size384, 12, 25, 63} {
|
||||
for i := 0; i < 256; i++ {
|
||||
h, err := New(size, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
|
||||
}
|
||||
h2, err := New(size, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
|
||||
}
|
||||
|
||||
h.Write(input[:i/2])
|
||||
halfstate, err := h.(encoding.BinaryMarshaler).MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatalf("size=%d, len(input)=%d: could not marshal: %v", size, i, err)
|
||||
}
|
||||
err = h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(halfstate)
|
||||
if err != nil {
|
||||
t.Fatalf("size=%d, len(input)=%d: could not unmarshal: %v", size, i, err)
|
||||
}
|
||||
|
||||
h.Write(input[i/2 : i])
|
||||
sum := h.Sum(nil)
|
||||
h2.Write(input[i/2 : i])
|
||||
sum2 := h2.Sum(nil)
|
||||
|
||||
if !bytes.Equal(sum, sum2) {
|
||||
t.Fatalf("size=%d, len(input)=%d: results do not match; sum = %v, sum2 = %v", size, i, sum, sum2)
|
||||
}
|
||||
|
||||
h3, err := New(size, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err)
|
||||
}
|
||||
h3.Write(input[:i])
|
||||
sum3 := h3.Sum(nil)
|
||||
if !bytes.Equal(sum, sum3) {
|
||||
t.Fatalf("size=%d, len(input)=%d: sum = %v, want %v", size, i, sum, sum3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testHashes(t *testing.T) {
|
||||
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
|
||||
|
||||
|
2
vendor/golang.org/x/crypto/blake2b/blake2x.go
generated
vendored
2
vendor/golang.org/x/crypto/blake2b/blake2x.go
generated
vendored
@ -29,7 +29,7 @@ type XOF interface {
|
||||
}
|
||||
|
||||
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
|
||||
// the the length of the output is not known in advance.
|
||||
// the length of the output is not known in advance.
|
||||
const OutputLengthUnknown = 0
|
||||
|
||||
// magicUnknownOutputLength is a magic value for the output size that indicates
|
||||
|
57
vendor/golang.org/x/crypto/blake2s/blake2s.go
generated
vendored
57
vendor/golang.org/x/crypto/blake2s/blake2s.go
generated
vendored
@ -49,6 +49,8 @@ func Sum256(data []byte) [Size]byte {
|
||||
|
||||
// New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 32 bytes long.
|
||||
// When the key is nil, the returned hash.Hash implements BinaryMarshaler
|
||||
// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
|
||||
func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
||||
|
||||
// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
|
||||
@ -120,6 +122,50 @@ type digest struct {
|
||||
keyLen int
|
||||
}
|
||||
|
||||
const (
|
||||
magic = "b2s"
|
||||
marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1
|
||||
)
|
||||
|
||||
func (d *digest) MarshalBinary() ([]byte, error) {
|
||||
if d.keyLen != 0 {
|
||||
return nil, errors.New("crypto/blake2s: cannot marshal MACs")
|
||||
}
|
||||
b := make([]byte, 0, marshaledSize)
|
||||
b = append(b, magic...)
|
||||
for i := 0; i < 8; i++ {
|
||||
b = appendUint32(b, d.h[i])
|
||||
}
|
||||
b = appendUint32(b, d.c[0])
|
||||
b = appendUint32(b, d.c[1])
|
||||
// Maximum value for size is 32
|
||||
b = append(b, byte(d.size))
|
||||
b = append(b, d.block[:]...)
|
||||
b = append(b, byte(d.offset))
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (d *digest) UnmarshalBinary(b []byte) error {
|
||||
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
|
||||
return errors.New("crypto/blake2s: invalid hash state identifier")
|
||||
}
|
||||
if len(b) != marshaledSize {
|
||||
return errors.New("crypto/blake2s: invalid hash state size")
|
||||
}
|
||||
b = b[len(magic):]
|
||||
for i := 0; i < 8; i++ {
|
||||
b, d.h[i] = consumeUint32(b)
|
||||
}
|
||||
b, d.c[0] = consumeUint32(b)
|
||||
b, d.c[1] = consumeUint32(b)
|
||||
d.size = int(b[0])
|
||||
b = b[1:]
|
||||
copy(d.block[:], b[:BlockSize])
|
||||
b = b[BlockSize:]
|
||||
d.offset = int(b[0])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Size() int { return d.size }
|
||||
@ -185,3 +231,14 @@ func (d *digest) finalize(hash *[Size]byte) {
|
||||
binary.LittleEndian.PutUint32(hash[4*i:], v)
|
||||
}
|
||||
}
|
||||
|
||||
func appendUint32(b []byte, x uint32) []byte {
|
||||
var a [4]byte
|
||||
binary.BigEndian.PutUint32(a[:], x)
|
||||
return append(b, a[:]...)
|
||||
}
|
||||
|
||||
func consumeUint32(b []byte) ([]byte, uint32) {
|
||||
x := binary.BigEndian.Uint32(b)
|
||||
return b[4:], x
|
||||
}
|
||||
|
19
vendor/golang.org/x/crypto/blake2s/blake2s_386.go
generated
vendored
19
vendor/golang.org/x/crypto/blake2s/blake2s_386.go
generated
vendored
@ -6,18 +6,14 @@
|
||||
|
||||
package blake2s
|
||||
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
var (
|
||||
useSSE4 = false
|
||||
useSSSE3 = supportSSSE3()
|
||||
useSSE2 = supportSSE2()
|
||||
useSSSE3 = cpu.X86.HasSSSE3
|
||||
useSSE2 = cpu.X86.HasSSE2
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func supportSSE2() bool
|
||||
|
||||
//go:noescape
|
||||
func supportSSSE3() bool
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
@ -25,11 +21,12 @@ func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
|
||||
if useSSSE3 {
|
||||
switch {
|
||||
case useSSSE3:
|
||||
hashBlocksSSSE3(h, c, flag, blocks)
|
||||
} else if useSSE2 {
|
||||
case useSSE2:
|
||||
hashBlocksSSE2(h, c, flag, blocks)
|
||||
} else {
|
||||
default:
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
||||
}
|
||||
|
25
vendor/golang.org/x/crypto/blake2s/blake2s_386.s
generated
vendored
25
vendor/golang.org/x/crypto/blake2s/blake2s_386.s
generated
vendored
@ -433,28 +433,3 @@ loop:
|
||||
|
||||
MOVL BP, SP
|
||||
RET
|
||||
|
||||
// func supportSSSE3() bool
|
||||
TEXT ·supportSSSE3(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
MOVL CX, BX
|
||||
ANDL $0x1, BX // supports SSE3
|
||||
JZ FALSE
|
||||
ANDL $0x200, CX // supports SSSE3
|
||||
JZ FALSE
|
||||
MOVB $1, ret+0(FP)
|
||||
RET
|
||||
|
||||
FALSE:
|
||||
MOVB $0, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func supportSSE2() bool
|
||||
TEXT ·supportSSE2(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
SHRL $26, DX
|
||||
ANDL $1, DX // DX != 0 if support SSE2
|
||||
MOVB DX, ret+0(FP)
|
||||
RET
|
||||
|
23
vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go
generated
vendored
23
vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go
generated
vendored
@ -6,18 +6,14 @@
|
||||
|
||||
package blake2s
|
||||
|
||||
import "golang.org/x/sys/cpu"
|
||||
|
||||
var (
|
||||
useSSE4 = supportSSE4()
|
||||
useSSSE3 = supportSSSE3()
|
||||
useSSE2 = true // Always available on amd64
|
||||
useSSE4 = cpu.X86.HasSSE41
|
||||
useSSSE3 = cpu.X86.HasSSSE3
|
||||
useSSE2 = cpu.X86.HasSSE2
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func supportSSSE3() bool
|
||||
|
||||
//go:noescape
|
||||
func supportSSE4() bool
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
@ -28,13 +24,14 @@ func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
|
||||
if useSSE4 {
|
||||
switch {
|
||||
case useSSE4:
|
||||
hashBlocksSSE4(h, c, flag, blocks)
|
||||
} else if useSSSE3 {
|
||||
case useSSSE3:
|
||||
hashBlocksSSSE3(h, c, flag, blocks)
|
||||
} else if useSSE2 {
|
||||
case useSSE2:
|
||||
hashBlocksSSE2(h, c, flag, blocks)
|
||||
} else {
|
||||
default:
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
||||
}
|
||||
|
25
vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s
generated
vendored
25
vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s
generated
vendored
@ -436,28 +436,3 @@ TEXT ·hashBlocksSSSE3(SB), 0, $672-48 // frame = 656 + 16 byte alignment
|
||||
TEXT ·hashBlocksSSE4(SB), 0, $32-48 // frame = 16 + 16 byte alignment
|
||||
HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE4)
|
||||
RET
|
||||
|
||||
// func supportSSE4() bool
|
||||
TEXT ·supportSSE4(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
SHRL $19, CX // Bit 19 indicates SSE4.1.
|
||||
ANDL $1, CX
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func supportSSSE3() bool
|
||||
TEXT ·supportSSSE3(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
MOVL CX, BX
|
||||
ANDL $0x1, BX // Bit zero indicates SSE3 support.
|
||||
JZ FALSE
|
||||
ANDL $0x200, CX // Bit nine indicates SSSE3 support.
|
||||
JZ FALSE
|
||||
MOVB $1, ret+0(FP)
|
||||
RET
|
||||
|
||||
FALSE:
|
||||
MOVB $0, ret+0(FP)
|
||||
RET
|
||||
|
48
vendor/golang.org/x/crypto/blake2s/blake2s_test.go
generated
vendored
48
vendor/golang.org/x/crypto/blake2s/blake2s_test.go
generated
vendored
@ -5,6 +5,8 @@
|
||||
package blake2s
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
@ -64,6 +66,52 @@ func TestHashes2X(t *testing.T) {
|
||||
testHashes2X(t)
|
||||
}
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
input := make([]byte, 255)
|
||||
for i := range input {
|
||||
input[i] = byte(i)
|
||||
}
|
||||
for i := 0; i < 256; i++ {
|
||||
h, err := New256(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err)
|
||||
}
|
||||
h2, err := New256(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err)
|
||||
}
|
||||
|
||||
h.Write(input[:i/2])
|
||||
halfstate, err := h.(encoding.BinaryMarshaler).MarshalBinary()
|
||||
if err != nil {
|
||||
t.Fatalf("len(input)=%d: could not marshal: %v", i, err)
|
||||
}
|
||||
err = h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(halfstate)
|
||||
if err != nil {
|
||||
t.Fatalf("len(input)=%d: could not unmarshal: %v", i, err)
|
||||
}
|
||||
|
||||
h.Write(input[i/2 : i])
|
||||
sum := h.Sum(nil)
|
||||
h2.Write(input[i/2 : i])
|
||||
sum2 := h2.Sum(nil)
|
||||
|
||||
if !bytes.Equal(sum, sum2) {
|
||||
t.Fatalf("len(input)=%d: results do not match; sum = %v, sum2 = %v", i, sum, sum2)
|
||||
}
|
||||
|
||||
h3, err := New256(nil)
|
||||
if err != nil {
|
||||
t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err)
|
||||
}
|
||||
h3.Write(input[:i])
|
||||
sum3 := h3.Sum(nil)
|
||||
if !bytes.Equal(sum, sum3) {
|
||||
t.Fatalf("len(input)=%d: sum = %v, want %v", i, sum, sum3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testHashes(t *testing.T) {
|
||||
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
|
||||
|
||||
|
2
vendor/golang.org/x/crypto/blake2s/blake2x.go
generated
vendored
2
vendor/golang.org/x/crypto/blake2s/blake2x.go
generated
vendored
@ -29,7 +29,7 @@ type XOF interface {
|
||||
}
|
||||
|
||||
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
|
||||
// the the length of the output is not known in advance.
|
||||
// the length of the output is not known in advance.
|
||||
const OutputLengthUnknown = 0
|
||||
|
||||
// magicUnknownOutputLength is a magic value for the output size that indicates
|
||||
|
8
vendor/golang.org/x/crypto/blowfish/cipher.go
generated
vendored
8
vendor/golang.org/x/crypto/blowfish/cipher.go
generated
vendored
@ -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.
|
||||
|
51
vendor/golang.org/x/crypto/bn256/bn256.go
generated
vendored
51
vendor/golang.org/x/crypto/bn256/bn256.go
generated
vendored
@ -15,9 +15,14 @@
|
||||
// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible
|
||||
// with the implementation described in that paper.
|
||||
//
|
||||
// (This package previously claimed to operate at a 128-bit security level.
|
||||
// This package previously claimed to operate at a 128-bit security level.
|
||||
// However, recent improvements in attacks mean that is no longer true. See
|
||||
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.)
|
||||
// https://moderncrypto.org/mail-archive/curves/2016/000740.html.
|
||||
//
|
||||
// Deprecated: due to its weakened security, new systems should not rely on this
|
||||
// elliptic curve. This package is frozen, and not implemented in constant time.
|
||||
// There is a more complete implementation at github.com/cloudflare/bn256, but
|
||||
// note that it suffers from the same security issues of the underlying curve.
|
||||
package bn256 // import "golang.org/x/crypto/bn256"
|
||||
|
||||
import (
|
||||
@ -26,9 +31,6 @@ import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// BUG(agl): this implementation is not constant time.
|
||||
// TODO(agl): keep GF(p²) elements in Mongomery form.
|
||||
|
||||
// G1 is an abstract cyclic group. The zero value is suitable for use as the
|
||||
// output of an operation, but cannot be used as an input.
|
||||
type G1 struct {
|
||||
@ -54,6 +56,9 @@ func RandomG1(r io.Reader) (*big.Int, *G1, error) {
|
||||
}
|
||||
|
||||
func (e *G1) String() string {
|
||||
if e.p == nil {
|
||||
return "bn256.G1" + newCurvePoint(nil).String()
|
||||
}
|
||||
return "bn256.G1" + e.p.String()
|
||||
}
|
||||
|
||||
@ -77,7 +82,8 @@ func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
|
||||
}
|
||||
|
||||
// Add sets e to a+b and then returns e.
|
||||
// BUG(agl): this function is not complete: a==b fails.
|
||||
//
|
||||
// Warning: this function is not complete, it fails for a equal to b.
|
||||
func (e *G1) Add(a, b *G1) *G1 {
|
||||
if e.p == nil {
|
||||
e.p = newCurvePoint(nil)
|
||||
@ -97,14 +103,18 @@ func (e *G1) Neg(a *G1) *G1 {
|
||||
|
||||
// Marshal converts n to a byte slice.
|
||||
func (e *G1) Marshal() []byte {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
if e.p.IsInfinity() {
|
||||
return make([]byte, numBytes*2)
|
||||
}
|
||||
|
||||
e.p.MakeAffine(nil)
|
||||
|
||||
xBytes := new(big.Int).Mod(e.p.x, p).Bytes()
|
||||
yBytes := new(big.Int).Mod(e.p.y, p).Bytes()
|
||||
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
ret := make([]byte, numBytes*2)
|
||||
copy(ret[1*numBytes-len(xBytes):], xBytes)
|
||||
copy(ret[2*numBytes-len(yBytes):], yBytes)
|
||||
@ -171,6 +181,9 @@ func RandomG2(r io.Reader) (*big.Int, *G2, error) {
|
||||
}
|
||||
|
||||
func (e *G2) String() string {
|
||||
if e.p == nil {
|
||||
return "bn256.G2" + newTwistPoint(nil).String()
|
||||
}
|
||||
return "bn256.G2" + e.p.String()
|
||||
}
|
||||
|
||||
@ -194,7 +207,8 @@ func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
|
||||
}
|
||||
|
||||
// Add sets e to a+b and then returns e.
|
||||
// BUG(agl): this function is not complete: a==b fails.
|
||||
//
|
||||
// Warning: this function is not complete, it fails for a equal to b.
|
||||
func (e *G2) Add(a, b *G2) *G2 {
|
||||
if e.p == nil {
|
||||
e.p = newTwistPoint(nil)
|
||||
@ -205,6 +219,13 @@ func (e *G2) Add(a, b *G2) *G2 {
|
||||
|
||||
// Marshal converts n into a byte slice.
|
||||
func (n *G2) Marshal() []byte {
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
if n.p.IsInfinity() {
|
||||
return make([]byte, numBytes*4)
|
||||
}
|
||||
|
||||
n.p.MakeAffine(nil)
|
||||
|
||||
xxBytes := new(big.Int).Mod(n.p.x.x, p).Bytes()
|
||||
@ -212,9 +233,6 @@ func (n *G2) Marshal() []byte {
|
||||
yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes()
|
||||
yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes()
|
||||
|
||||
// Each value is a 256-bit number.
|
||||
const numBytes = 256 / 8
|
||||
|
||||
ret := make([]byte, numBytes*4)
|
||||
copy(ret[1*numBytes-len(xxBytes):], xxBytes)
|
||||
copy(ret[2*numBytes-len(xyBytes):], xyBytes)
|
||||
@ -269,8 +287,11 @@ type GT struct {
|
||||
p *gfP12
|
||||
}
|
||||
|
||||
func (g *GT) String() string {
|
||||
return "bn256.GT" + g.p.String()
|
||||
func (e *GT) String() string {
|
||||
if e.p == nil {
|
||||
return "bn256.GT" + newGFp12(nil).String()
|
||||
}
|
||||
return "bn256.GT" + e.p.String()
|
||||
}
|
||||
|
||||
// ScalarMult sets e to a*k and then returns e.
|
||||
|
9
vendor/golang.org/x/crypto/bn256/curve.go
generated
vendored
9
vendor/golang.org/x/crypto/bn256/curve.go
generated
vendored
@ -245,10 +245,19 @@ func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoi
|
||||
return c
|
||||
}
|
||||
|
||||
// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
|
||||
// c to 0 : 1 : 0.
|
||||
func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
|
||||
if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
|
||||
return c
|
||||
}
|
||||
if c.IsInfinity() {
|
||||
c.x.SetInt64(0)
|
||||
c.y.SetInt64(1)
|
||||
c.z.SetInt64(0)
|
||||
c.t.SetInt64(0)
|
||||
return c
|
||||
}
|
||||
|
||||
zInv := pool.Get().ModInverse(c.z, p)
|
||||
t := pool.Get().Mul(c.y, zInv)
|
||||
|
4
vendor/golang.org/x/crypto/bn256/gfp12.go
generated
vendored
4
vendor/golang.org/x/crypto/bn256/gfp12.go
generated
vendored
@ -125,8 +125,8 @@ func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 {
|
||||
}
|
||||
|
||||
func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
|
||||
e.x.Mul(e.x, b, pool)
|
||||
e.y.Mul(e.y, b, pool)
|
||||
e.x.Mul(a.x, b, pool)
|
||||
e.y.Mul(a.y, b, pool)
|
||||
return e
|
||||
}
|
||||
|
||||
|
9
vendor/golang.org/x/crypto/bn256/twist.go
generated
vendored
9
vendor/golang.org/x/crypto/bn256/twist.go
generated
vendored
@ -219,10 +219,19 @@ func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoi
|
||||
return c
|
||||
}
|
||||
|
||||
// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets
|
||||
// c to 0 : 1 : 0.
|
||||
func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint {
|
||||
if c.z.IsOne() {
|
||||
return c
|
||||
}
|
||||
if c.IsInfinity() {
|
||||
c.x.SetZero()
|
||||
c.y.SetOne()
|
||||
c.z.SetZero()
|
||||
c.t.SetZero()
|
||||
return c
|
||||
}
|
||||
|
||||
zInv := newGFp2(pool).Invert(c.z, pool)
|
||||
t := newGFp2(pool).Mul(c.y, zInv, pool)
|
||||
|
11
vendor/golang.org/x/crypto/cast5/cast5.go
generated
vendored
11
vendor/golang.org/x/crypto/cast5/cast5.go
generated
vendored
@ -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"
|
||||
|
28
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
generated
vendored
28
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
generated
vendored
@ -2,32 +2,50 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539.
|
||||
// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539,
|
||||
// and its extended nonce variant XChaCha20-Poly1305.
|
||||
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// KeySize is the size of the key used by this AEAD, in bytes.
|
||||
KeySize = 32
|
||||
// NonceSize is the size of the nonce used with this AEAD, in bytes.
|
||||
|
||||
// NonceSize is the size of the nonce used with the standard variant of this
|
||||
// AEAD, in bytes.
|
||||
//
|
||||
// Note that this is too short to be safely generated at random if the same
|
||||
// key is reused more than 2³² times.
|
||||
NonceSize = 12
|
||||
|
||||
// NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305
|
||||
// variant of this AEAD, in bytes.
|
||||
NonceSizeX = 24
|
||||
)
|
||||
|
||||
type chacha20poly1305 struct {
|
||||
key [32]byte
|
||||
key [8]uint32
|
||||
}
|
||||
|
||||
// New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key.
|
||||
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
|
||||
func New(key []byte) (cipher.AEAD, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
ret := new(chacha20poly1305)
|
||||
copy(ret.key[:], key)
|
||||
ret.key[0] = binary.LittleEndian.Uint32(key[0:4])
|
||||
ret.key[1] = binary.LittleEndian.Uint32(key[4:8])
|
||||
ret.key[2] = binary.LittleEndian.Uint32(key[8:12])
|
||||
ret.key[3] = binary.LittleEndian.Uint32(key[12:16])
|
||||
ret.key[4] = binary.LittleEndian.Uint32(key[16:20])
|
||||
ret.key[5] = binary.LittleEndian.Uint32(key[20:24])
|
||||
ret.key[6] = binary.LittleEndian.Uint32(key[24:28])
|
||||
ret.key[7] = binary.LittleEndian.Uint32(key[28:32])
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
89
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
89
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
@ -6,7 +6,12 @@
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import "encoding/binary"
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||
@ -14,78 +19,26 @@ func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||
//go:noescape
|
||||
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
||||
|
||||
// cpuid is implemented in chacha20poly1305_amd64.s.
|
||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||
|
||||
// xgetbv with ecx = 0 is implemented in chacha20poly1305_amd64.s.
|
||||
func xgetbv() (eax, edx uint32)
|
||||
|
||||
var (
|
||||
useASM bool
|
||||
useAVX2 bool
|
||||
useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
|
||||
)
|
||||
|
||||
func init() {
|
||||
detectCPUFeatures()
|
||||
}
|
||||
|
||||
// detectCPUFeatures is used to detect if cpu instructions
|
||||
// used by the functions implemented in assembler in
|
||||
// chacha20poly1305_amd64.s are supported.
|
||||
func detectCPUFeatures() {
|
||||
maxID, _, _, _ := cpuid(0, 0)
|
||||
if maxID < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
_, _, ecx1, _ := cpuid(1, 0)
|
||||
|
||||
haveSSSE3 := isSet(9, ecx1)
|
||||
useASM = haveSSSE3
|
||||
|
||||
haveOSXSAVE := isSet(27, ecx1)
|
||||
|
||||
osSupportsAVX := false
|
||||
// For XGETBV, OSXSAVE bit is required and sufficient.
|
||||
if haveOSXSAVE {
|
||||
eax, _ := xgetbv()
|
||||
// Check if XMM and YMM registers have OS support.
|
||||
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
||||
}
|
||||
haveAVX := isSet(28, ecx1) && osSupportsAVX
|
||||
|
||||
if maxID < 7 {
|
||||
return
|
||||
}
|
||||
|
||||
_, ebx7, _, _ := cpuid(7, 0)
|
||||
haveAVX2 := isSet(5, ebx7) && haveAVX
|
||||
haveBMI2 := isSet(8, ebx7)
|
||||
|
||||
useAVX2 = haveAVX2 && haveBMI2
|
||||
}
|
||||
|
||||
// isSet checks if bit at bitpos is set in value.
|
||||
func isSet(bitpos uint, value uint32) bool {
|
||||
return value&(1<<bitpos) != 0
|
||||
}
|
||||
|
||||
// setupState writes a ChaCha20 input matrix to state. See
|
||||
// https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
||||
func setupState(state *[16]uint32, key *[8]uint32, nonce []byte) {
|
||||
state[0] = 0x61707865
|
||||
state[1] = 0x3320646e
|
||||
state[2] = 0x79622d32
|
||||
state[3] = 0x6b206574
|
||||
|
||||
state[4] = binary.LittleEndian.Uint32(key[:4])
|
||||
state[5] = binary.LittleEndian.Uint32(key[4:8])
|
||||
state[6] = binary.LittleEndian.Uint32(key[8:12])
|
||||
state[7] = binary.LittleEndian.Uint32(key[12:16])
|
||||
state[8] = binary.LittleEndian.Uint32(key[16:20])
|
||||
state[9] = binary.LittleEndian.Uint32(key[20:24])
|
||||
state[10] = binary.LittleEndian.Uint32(key[24:28])
|
||||
state[11] = binary.LittleEndian.Uint32(key[28:32])
|
||||
state[4] = key[0]
|
||||
state[5] = key[1]
|
||||
state[6] = key[2]
|
||||
state[7] = key[3]
|
||||
state[8] = key[4]
|
||||
state[9] = key[5]
|
||||
state[10] = key[6]
|
||||
state[11] = key[7]
|
||||
|
||||
state[12] = 0
|
||||
state[13] = binary.LittleEndian.Uint32(nonce[:4])
|
||||
@ -94,7 +47,7 @@ func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if !useASM {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
@ -102,12 +55,15 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
|
||||
setupState(&state, &c.key, nonce)
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||
if subtle.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if !useASM {
|
||||
if !cpu.X86.HasSSSE3 {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
@ -116,6 +72,9 @@ func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) (
|
||||
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if subtle.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
|
19
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
19
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
@ -2693,22 +2693,3 @@ sealAVX2Tail512LoopB:
|
||||
VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
|
||||
|
||||
JMP sealAVX2SealHash
|
||||
|
||||
// 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
|
||||
|
37
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
37
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
@ -8,6 +8,7 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/internal/chacha20"
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
)
|
||||
|
||||
@ -16,15 +17,20 @@ func roundTo16(n int) int {
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
var counter [16]byte
|
||||
copy(counter[4:], nonce)
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
if subtle.InexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
|
||||
var polyKey [32]byte
|
||||
chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
counter[0] = 1
|
||||
chacha20.XORKeyStream(out, plaintext, &counter, &c.key)
|
||||
s := chacha20.New(c.key, [3]uint32{
|
||||
binary.LittleEndian.Uint32(nonce[0:4]),
|
||||
binary.LittleEndian.Uint32(nonce[4:8]),
|
||||
binary.LittleEndian.Uint32(nonce[8:12]),
|
||||
})
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.Advance() // skip the next 32 bytes
|
||||
s.XORKeyStream(out, plaintext)
|
||||
|
||||
polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
|
||||
copy(polyInput, additionalData)
|
||||
@ -44,11 +50,14 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
|
||||
copy(tag[:], ciphertext[len(ciphertext)-16:])
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
|
||||
var counter [16]byte
|
||||
copy(counter[4:], nonce)
|
||||
|
||||
var polyKey [32]byte
|
||||
chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
|
||||
s := chacha20.New(c.key, [3]uint32{
|
||||
binary.LittleEndian.Uint32(nonce[0:4]),
|
||||
binary.LittleEndian.Uint32(nonce[4:8]),
|
||||
binary.LittleEndian.Uint32(nonce[8:12]),
|
||||
})
|
||||
s.XORKeyStream(polyKey[:], polyKey[:])
|
||||
s.Advance() // skip the next 32 bytes
|
||||
|
||||
polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
|
||||
copy(polyInput, additionalData)
|
||||
@ -57,6 +66,9 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
|
||||
binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
|
||||
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if subtle.InexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap")
|
||||
}
|
||||
if !poly1305.Verify(&tag, polyInput, &polyKey) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
@ -64,7 +76,6 @@ func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
counter[0] = 1
|
||||
chacha20.XORKeyStream(out, ciphertext, &counter, &c.key)
|
||||
s.XORKeyStream(out, ciphertext)
|
||||
return ret, nil
|
||||
}
|
||||
|
223
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
generated
vendored
223
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
generated
vendored
@ -6,9 +6,13 @@ package chacha20poly1305
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
cr "crypto/rand"
|
||||
"crypto/cipher"
|
||||
cryptorand "crypto/rand"
|
||||
"encoding/hex"
|
||||
mr "math/rand"
|
||||
"fmt"
|
||||
"log"
|
||||
mathrand "math/rand"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -19,7 +23,18 @@ func TestVectors(t *testing.T) {
|
||||
ad, _ := hex.DecodeString(test.aad)
|
||||
plaintext, _ := hex.DecodeString(test.plaintext)
|
||||
|
||||
aead, err := New(key)
|
||||
var (
|
||||
aead cipher.AEAD
|
||||
err error
|
||||
)
|
||||
switch len(nonce) {
|
||||
case NonceSize:
|
||||
aead, err = New(key)
|
||||
case NonceSizeX:
|
||||
aead, err = NewX(key)
|
||||
default:
|
||||
t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce))
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -42,7 +57,7 @@ func TestVectors(t *testing.T) {
|
||||
}
|
||||
|
||||
if len(ad) > 0 {
|
||||
alterAdIdx := mr.Intn(len(ad))
|
||||
alterAdIdx := mathrand.Intn(len(ad))
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering additional data", i)
|
||||
@ -50,14 +65,14 @@ func TestVectors(t *testing.T) {
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
}
|
||||
|
||||
alterNonceIdx := mr.Intn(aead.NonceSize())
|
||||
alterNonceIdx := mathrand.Intn(aead.NonceSize())
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering nonce", i)
|
||||
}
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
|
||||
alterCtIdx := mr.Intn(len(ct))
|
||||
alterCtIdx := mathrand.Intn(len(ct))
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering ciphertext", i)
|
||||
@ -68,87 +83,117 @@ func TestVectors(t *testing.T) {
|
||||
|
||||
func TestRandom(t *testing.T) {
|
||||
// Some random tests to verify Open(Seal) == Plaintext
|
||||
for i := 0; i < 256; i++ {
|
||||
var nonce [12]byte
|
||||
var key [32]byte
|
||||
f := func(t *testing.T, nonceSize int) {
|
||||
for i := 0; i < 256; i++ {
|
||||
var nonce = make([]byte, nonceSize)
|
||||
var key [32]byte
|
||||
|
||||
al := mr.Intn(128)
|
||||
pl := mr.Intn(16384)
|
||||
ad := make([]byte, al)
|
||||
plaintext := make([]byte, pl)
|
||||
cr.Read(key[:])
|
||||
cr.Read(nonce[:])
|
||||
cr.Read(ad)
|
||||
cr.Read(plaintext)
|
||||
al := mathrand.Intn(128)
|
||||
pl := mathrand.Intn(16384)
|
||||
ad := make([]byte, al)
|
||||
plaintext := make([]byte, pl)
|
||||
cryptorand.Read(key[:])
|
||||
cryptorand.Read(nonce[:])
|
||||
cryptorand.Read(ad)
|
||||
cryptorand.Read(plaintext)
|
||||
|
||||
aead, err := New(key[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ct := aead.Seal(nil, nonce[:], plaintext, ad)
|
||||
|
||||
plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
|
||||
if err != nil {
|
||||
t.Errorf("Random #%d: Open failed", i)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(plaintext, plaintext2) {
|
||||
t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(ad) > 0 {
|
||||
alterAdIdx := mr.Intn(len(ad))
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering additional data", i)
|
||||
var (
|
||||
aead cipher.AEAD
|
||||
err error
|
||||
)
|
||||
switch len(nonce) {
|
||||
case NonceSize:
|
||||
aead, err = New(key[:])
|
||||
case NonceSizeX:
|
||||
aead, err = NewX(key[:])
|
||||
default:
|
||||
t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce))
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
}
|
||||
|
||||
alterNonceIdx := mr.Intn(aead.NonceSize())
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering nonce", i)
|
||||
}
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
ct := aead.Seal(nil, nonce[:], plaintext, ad)
|
||||
|
||||
alterCtIdx := mr.Intn(len(ct))
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
|
||||
plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
|
||||
if err != nil {
|
||||
t.Errorf("Random #%d: Open failed", i)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(plaintext, plaintext2) {
|
||||
t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(ad) > 0 {
|
||||
alterAdIdx := mathrand.Intn(len(ad))
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering additional data", i)
|
||||
}
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
}
|
||||
|
||||
alterNonceIdx := mathrand.Intn(aead.NonceSize())
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering nonce", i)
|
||||
}
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
|
||||
alterCtIdx := mathrand.Intn(len(ct))
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
|
||||
}
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
}
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
}
|
||||
t.Run("Standard", func(t *testing.T) { f(t, NonceSize) })
|
||||
t.Run("X", func(t *testing.T) { f(t, NonceSizeX) })
|
||||
}
|
||||
|
||||
func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte) {
|
||||
func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) {
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [32]byte
|
||||
var nonce [12]byte
|
||||
var nonce = make([]byte, nonceSize)
|
||||
var ad [13]byte
|
||||
var out []byte
|
||||
|
||||
aead, _ := New(key[:])
|
||||
var aead cipher.AEAD
|
||||
switch len(nonce) {
|
||||
case NonceSize:
|
||||
aead, _ = New(key[:])
|
||||
case NonceSizeX:
|
||||
aead, _ = NewX(key[:])
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
out = aead.Seal(out[:0], nonce[:], buf[:], ad[:])
|
||||
}
|
||||
}
|
||||
|
||||
func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) {
|
||||
func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) {
|
||||
b.ReportAllocs()
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [32]byte
|
||||
var nonce [12]byte
|
||||
var nonce = make([]byte, nonceSize)
|
||||
var ad [13]byte
|
||||
var ct []byte
|
||||
var out []byte
|
||||
|
||||
aead, _ := New(key[:])
|
||||
var aead cipher.AEAD
|
||||
switch len(nonce) {
|
||||
case NonceSize:
|
||||
aead, _ = New(key[:])
|
||||
case NonceSizeX:
|
||||
aead, _ = NewX(key[:])
|
||||
}
|
||||
ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:])
|
||||
|
||||
b.ResetTimer()
|
||||
@ -157,26 +202,54 @@ func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Open_64(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, 64))
|
||||
func BenchmarkChacha20Poly1305(b *testing.B) {
|
||||
for _, length := range []int{64, 1350, 8 * 1024} {
|
||||
b.Run("Open-"+strconv.Itoa(length), func(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSize)
|
||||
})
|
||||
b.Run("Seal-"+strconv.Itoa(length), func(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSize)
|
||||
})
|
||||
|
||||
b.Run("Open-"+strconv.Itoa(length)+"-X", func(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSizeX)
|
||||
})
|
||||
b.Run("Seal-"+strconv.Itoa(length)+"-X", func(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSizeX)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Seal_64(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, 64))
|
||||
}
|
||||
var key = make([]byte, KeySize)
|
||||
|
||||
func BenchmarkChacha20Poly1305Open_1350(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, 1350))
|
||||
}
|
||||
func ExampleNewX() {
|
||||
aead, err := NewX(key)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to instantiate XChaCha20-Poly1305:", err)
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Seal_1350(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, 1350))
|
||||
}
|
||||
for _, msg := range []string{
|
||||
"Attack at dawn.",
|
||||
"The eagle has landed.",
|
||||
"Gophers, gophers, gophers everywhere!",
|
||||
} {
|
||||
// Encryption.
|
||||
nonce := make([]byte, NonceSizeX)
|
||||
if _, err := cryptorand.Read(nonce); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ciphertext := aead.Seal(nil, nonce, []byte(msg), nil)
|
||||
|
||||
func BenchmarkChacha20Poly1305Open_8K(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, 8*1024))
|
||||
}
|
||||
// Decryption.
|
||||
plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to decrypt or authenticate message:", err)
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Seal_8K(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, 8*1024))
|
||||
fmt.Printf("%s\n", plaintext)
|
||||
}
|
||||
|
||||
// Output: Attack at dawn.
|
||||
// The eagle has landed.
|
||||
// Gophers, gophers, gophers everywhere!
|
||||
}
|
||||
|
394
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go
generated
vendored
394
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go
generated
vendored
@ -7,6 +7,13 @@ package chacha20poly1305
|
||||
var chacha20Poly1305Tests = []struct {
|
||||
plaintext, aad, key, nonce, out string
|
||||
}{
|
||||
{
|
||||
"",
|
||||
"",
|
||||
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
|
||||
"070000004041424344454647",
|
||||
"a0784d7a4716f3feb4f64e7f4b39bf04",
|
||||
},
|
||||
{
|
||||
"4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
|
||||
"50515253c0c1c2c3c4c5c6c7",
|
||||
@ -329,4 +336,391 @@ var chacha20Poly1305Tests = []struct {
|
||||
"129039b5572e8a7a8131f76a",
|
||||
"2c125232a59879aee36cacc4aca5085a4688c4f776667a8fbd86862b5cfb1d57c976688fdd652eafa2b88b1b8e358aa2110ff6ef13cdc1ceca9c9f087c35c38d89d6fbd8de89538070f17916ecb19ca3ef4a1c834f0bdaa1df62aaabef2e117106787056c909e61ecd208357dd5c363f11c5d6cf24992cc873cf69f59360a820fcf290bd90b2cab24c47286acb4e1033962b6d41e562a206a94796a8ab1c6b8bade804ff9bdf5ba6062d2c1f8fe0f4dfc05720bd9a612b92c26789f9f6a7ce43f5e8e3aee99a9cd7d6c11eaa611983c36935b0dda57d898a60a0ab7c4b54",
|
||||
},
|
||||
|
||||
// XChaCha20-Poly1305 vectors
|
||||
{
|
||||
"000000000000000000000000000000",
|
||||
"",
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"000000000000000000000000000000000000000000000000",
|
||||
"789e9689e5208d7fd9e1f3c5b5341fb2f7033812ac9ebd3745e2c99c7bbfeb",
|
||||
},
|
||||
{
|
||||
"02dc819b71875e49f5e1e5a768141cfd3f14307ae61a34d81decd9a3367c00c7",
|
||||
"",
|
||||
"b7bbfe61b8041658ddc95d5cbdc01bbe7626d24f3a043b70ddee87541234cff7",
|
||||
"e293239d4c0a07840c5f83cb515be7fd59c333933027e99c",
|
||||
"7a51f271bd2e547943c7be3316c05519a5d16803712289aa2369950b1504dd8267222e47b13280077ecada7b8795d535",
|
||||
},
|
||||
{
|
||||
"7afc5f3f24155002e17dc176a8f1f3a097ff5a991b02ff4640f70b90db0c15c328b696d6998ea7988edfe3b960e47824e4ae002fbe589be57896a9b7bf5578599c6ba0153c7c",
|
||||
"d499bb9758debe59a93783c61974b7",
|
||||
"4ea8fab44a07f7ffc0329b2c2f8f994efdb6d505aec32113ae324def5d929ba1",
|
||||
"404d5086271c58bf27b0352a205d21ce4367d7b6a7628961",
|
||||
"26d2b46ad58b6988e2dcf1d09ba8ab6f532dc7e0847cdbc0ed00284225c02bbdb278ee8381ebd127a06926107d1b731cfb1521b267168926492e8f77219ad922257a5be2c5e52e6183ca4dfd0ad3912d7bd1ec968065",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"",
|
||||
"48d8bd02c2e9947eae58327114d35e055407b5519c8019535efcb4fc875b5e2b",
|
||||
"cc0a587a475caba06f8dbc09afec1462af081fe1908c2cba",
|
||||
"fc3322d0a9d6fac3eb4a9e09b00b361e",
|
||||
},
|
||||
{
|
||||
"e0862731e5",
|
||||
"",
|
||||
"6579e7ee96151131a1fcd06fe0d52802c0021f214960ecceec14b2b8591f62cd",
|
||||
"e2230748649bc22e2b71e46a7814ecabe3a7005e949bd491",
|
||||
"e991efb85d8b1cfa3f92cb72b8d3c882e88f4529d9",
|
||||
},
|
||||
{
|
||||
"00c7dd8f440af1530b44",
|
||||
"",
|
||||
"ffb733657c849d50ab4ab40c4ae18f8ee2f0acf7c907afefdc04dff3537fdff3",
|
||||
"02c6fd8032a8d89edbedcd1db024c09d29f08b1e74325085",
|
||||
"13dbcdb8c60c3ed28449a57688edfaea89e309ab4faa6d51e532",
|
||||
},
|
||||
{
|
||||
"7422f311ea476cf819cb8b3c77369f",
|
||||
"",
|
||||
"ef0d05d028d6abdd5e99d1761d2028de75ee6eb376ff0dc8036e9a8e10743876",
|
||||
"f772745200b0f92e38f1d8dae79bf8138e84b301f0be74df",
|
||||
"d5f992f9834df1be86b580ac59c7eae063a68072829c51bc8a26970dd3d310",
|
||||
},
|
||||
{
|
||||
"ba09ca69450e6c7bece31a7a3f216e3b9ed0e536",
|
||||
"",
|
||||
"8d93e31abfe22a63faf45cbea91877050718f13fef6e2664a1892d7f23007ccf",
|
||||
"260b7b3554a7e6ff8aae7dd6234077ca539689a20c1610a8",
|
||||
"c99e9a768eb2ec8569bdff8a37295069552faebcafb1a76e98bc7c5b6b778b3d1b6291f0",
|
||||
},
|
||||
{
|
||||
"424ec5f98a0fdc5a7388532d11ab0edb26733505627b7f2d1f",
|
||||
"",
|
||||
"b68d5e6c46cdbb0060445522bdc5c562ae803b6aaaf1e103c146e93527a59299",
|
||||
"80bb5dc1dd44a35ec4f91307f1a95b4ca31183a1a596fb7c",
|
||||
"29d4eed0fff0050d4bb40de3b055d836206e7cbd62de1a63904f0cf731129ba3f9c2b9d46251a6de89",
|
||||
},
|
||||
{
|
||||
"e7e4515cc0a6ef0491af983eaac4f862d6e726758a3c657f4ec444841e42",
|
||||
"",
|
||||
"e31a1d3af650e8e2848bd78432d89ecd1fdece9842dc2792e7bda080f537b17b",
|
||||
"f3f09905e9a871e757348834f483ed71be9c0f437c8d74b0",
|
||||
"f5c69528963e17db725a28885d30a45194f12848b8b7644c7bded47a2ee83e6d4ef34006305cfdf82effdced461d",
|
||||
},
|
||||
{
|
||||
"0f5ca45a54875d1d19e952e53caeaa19389342f776dab11723535503338d6f77202a37",
|
||||
"",
|
||||
"1031bc920d4fcb4434553b1bf2d25ab375200643bf523ff037bf8914297e8dca",
|
||||
"4cc77e2ef5445e07b5f44de2dc5bf62d35b8c6f69502d2bf",
|
||||
"7aa8669e1bfe8b0688899cdddbb8cee31265928c66a69a5090478da7397573b1cc0f64121e7d8bff8db0ddd3c17460d7f29a12",
|
||||
},
|
||||
{
|
||||
"c45578c04c194994e89025c7ffb015e5f138be3cd1a93640af167706aee2ad25ad38696df41ad805",
|
||||
"",
|
||||
"ac8648b7c94328419c668ce1c57c71893adf73abbb98892a4fc8da17400e3a5e",
|
||||
"4ad637facf97af5fc03207ae56219da9972858b7430b3611",
|
||||
"49e093fcd074fb67a755669119b8bd430d98d9232ca988882deeb3508bde7c00160c35cea89092db864dcb6d440aefa5aacb8aa7b9c04cf0",
|
||||
},
|
||||
{
|
||||
"b877bfa192ea7e4c7569b9ee973f89924d45f9d8ed03c7098ad0cad6e7880906befedcaf6417bb43efabca7a2f",
|
||||
"",
|
||||
"125e331d5da423ecabc8adf693cdbc2fc3d3589740d40a3894f914db86c02492",
|
||||
"913f8b2f08006e6260de41ec3ee01d938a3e68fb12dc44c4",
|
||||
"1be334253423c90fc8ea885ee5cd3a54268c035ba8a2119e5bd4f7822cd7bf9cb4cec568d5b6d6292606d32979e044df3504e6eb8c0b2fc7e2a0e17d62",
|
||||
},
|
||||
{
|
||||
"d946484a1df5f85ff72c92ff9e192660cde5074bd0ddd5de900c35eb10ed991113b1b19884631bc8ceb386bcd83908061ce9",
|
||||
"",
|
||||
"b7e83276373dcf8929b6a6ea80314c9de871f5f241c9144189ee4caf62726332",
|
||||
"f59f9d6e3e6c00720dc20dc21586e8330431ebf42cf9180e",
|
||||
"a38a662b18c2d15e1b7b14443cc23267a10bee23556b084b6254226389c414069b694159a4d0b5abbe34de381a0e2c88b947b4cfaaebf50c7a1ad6c656e386280ad7",
|
||||
},
|
||||
{
|
||||
"d266927ca40b2261d5a4722f3b4da0dd5bec74e103fab431702309fd0d0f1a259c767b956aa7348ca923d64c04f0a2e898b0670988b15e",
|
||||
"",
|
||||
"a60e09cd0bea16f26e54b62b2908687aa89722c298e69a3a22cf6cf1c46b7f8a",
|
||||
"92da9d67854c53597fc099b68d955be32df2f0d9efe93614",
|
||||
"9dd6d05832f6b4d7f555a5a83930d6aed5423461d85f363efb6c474b6c4c8261b680dea393e24c2a3c8d1cc9db6df517423085833aa21f9ab5b42445b914f2313bcd205d179430",
|
||||
},
|
||||
{
|
||||
"f7e11b4d372ed7cb0c0e157f2f9488d8efea0f9bbe089a345f51bdc77e30d1392813c5d22ca7e2c7dfc2e2d0da67efb2a559058d4de7a11bd2a2915e",
|
||||
"",
|
||||
"194b1190fa31d483c222ec475d2d6117710dd1ac19a6f1a1e8e894885b7fa631",
|
||||
"6b07ea26bb1f2d92e04207b447f2fd1dd2086b442a7b6852",
|
||||
"25ae14585790d71d39a6e88632228a70b1f6a041839dc89a74701c06bfa7c4de3288b7772cb2919818d95777ab58fe5480d6e49958f5d2481431014a8f88dab8f7e08d2a9aebbe691430011d",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"1e2b11e3",
|
||||
"70cd96817da85ede0efdf03a358103a84561b25453dee73735e5fb0161b0d493",
|
||||
"5ddeba49f7266d11827a43931d1c300dd47a3c33f9f8bf9b",
|
||||
"592fc4c19f3cddec517b2a00f9df9665",
|
||||
},
|
||||
{
|
||||
"81b3cb7eb3",
|
||||
"efcfd0cf",
|
||||
"a977412f889281a6d75c24186f1bfaa00dcc5132f0929f20ef15bbf9e63c4c91",
|
||||
"3f26ca997fb9166d9c615babe3e543ca43ab7cab20634ac5",
|
||||
"8e4ade3e254cf52e93eace5c46667f150832725594",
|
||||
},
|
||||
{
|
||||
"556f97f2ebdb4e949923",
|
||||
"f7cee2e0",
|
||||
"787b3e86546a51028501c801dadf8d5b996fd6f6f2363d5d0f900c44f6a2f4c2",
|
||||
"7fa6af59a779657d1cada847439ea5b92a1337cfbebbc3b1",
|
||||
"608ec22dae5f48b89d6f0d2a940d5a7661e0a8e68aaee4ad2d96",
|
||||
},
|
||||
{
|
||||
"c06847a36ad031595b60edd44dc245",
|
||||
"d4175e1f",
|
||||
"16de31e534dd5af32801b1acd0ec541d1f8d82bcbc3af25ec815f3575b7aca73",
|
||||
"29f6656972838f56c1684f6a278f9e4e207b51d68706fc25",
|
||||
"836082cc51303e500fceade0b1a18f1d97d64ff41cc81754c07d6231b9fd1b",
|
||||
},
|
||||
{
|
||||
"0d03c22ced7b29c6741e72166cd61792028dfc80",
|
||||
"e505dad0",
|
||||
"ac2b426e5c5c8e00666180a3410e8a2f6e52247a43aecea9622163e8433c93b2",
|
||||
"c1123430468228625967bbc0fbd0f963e674372259ff2deb",
|
||||
"bf09979bf4fed2eec6c97f6e1bcfac35eeffc6d54a55cc1d83d8767ae74db2d7cdfbc371",
|
||||
},
|
||||
{
|
||||
"05bf00e1707cffe7ccbd06a9f846d0fd471a700ed43b4facb8",
|
||||
"d863bebe",
|
||||
"66c121f0f84b95ba1e6d29e7d81900bc96a642421b9b6105ae5eb5f2e7b07577",
|
||||
"8ed6ae211a661e967995b71f7316ba88f44322bb62b4187b",
|
||||
"b2c5c85d087e0305e9058fba52b661fb3d7f21cb4d4915ae048bc9e5d66a2f921dd4a1c1b030f442c9",
|
||||
},
|
||||
{
|
||||
"5f2b91a9be8bfaa21451ddc6c5cf28d1cc00b046b76270b95cda3c280c83",
|
||||
"a8750275",
|
||||
"39592eb276877fca9dd11e2181c0b23127328407e3cc11e315e5d748f43529cc",
|
||||
"1084bebd756f193d9eea608b3a0193a5028f8ced19684821",
|
||||
"eaee1f49ac8468154c601a5dd8b84d597602e5a73534b5fad5664f97d0f017dd114752be969679cf610340c6a312",
|
||||
},
|
||||
{
|
||||
"01e8e269b5376943f3b2d245483a76461dc8b7634868b559165f5dbb20839029fae9bb",
|
||||
"a1e96da0",
|
||||
"b8386123b87e50d9d046242cf1bf141fce7f65aff0fba76861a2bc72582d6ff0",
|
||||
"0fbe2a13a89bea031de96d78f9f11358ba7b6a5e724b4392",
|
||||
"705ec3f910ec85c6005baa99641de6ca43332ff52b5466df6af4ffbe4ef2a376a8f871d1eae503b5896601fee005cdc1f4c1c6",
|
||||
},
|
||||
{
|
||||
"706daba66e2edb1f828f3c0051e3cc214b12210bde0587bba02580f741a4c83e84d4e9fe961120cd",
|
||||
"87663c5a",
|
||||
"d519d82ba8a3f0c3af9efe36682b62e285167be101a526c1d73000f169c2a486",
|
||||
"ad651aac536978e2bc1a54816345ac5e9a9b43b3d9cc0bfc",
|
||||
"07051b5e72da9c4811beb07ff9f95aece67eae18420eb3f0e8bb8a5e26d4b483fa40eb063a2354842d0c8a41d981cc2b77c530b496db01c8",
|
||||
},
|
||||
{
|
||||
"1f6b24f2f0d9eb460d726bed953d66fcc4ecc29da6ed2fd711358eac3b2609d74ba3e21885156cde3cbe6d9b6f",
|
||||
"f5efbc4e",
|
||||
"86068a00544f749ad4ad15bb8e427ae78577ae22f4ca9778efff828ba10f6b20",
|
||||
"c8420412c9626dcd34ece14593730f6aa2d01ec51cacd59f",
|
||||
"a99f6c88eac35bb34439e34b292fe9db8192446dcdc81e2192060ec36d98b47de2bee12bf0f67cb24fb0949c07733a6781cd9455cdc61123f506886b04",
|
||||
},
|
||||
{
|
||||
"d69389d83362be8c0ddb738659a6cc4bd65d88cb5b525232f4d59a7d4751a7203c254923ecb6873e803220aab19664789a63",
|
||||
"bc35fb1c",
|
||||
"835855b326a98682b3075b4d7f1b89059c3cdfc547d4296c80ce7a77ba6434e3",
|
||||
"c27cb75fc319ba431cbaeb120341d0c4745d883eb47e92bc",
|
||||
"db6dc3f9a0f4f1a6df2495a88910550c2c6205478bfc1e81282e34b5b36d984c72c0509c522c987c61d2e640ced69402a6d33aa10d3d0b81e680b3c19bc142e81923",
|
||||
},
|
||||
{
|
||||
"a66a7f089115ed9e2d5bb5d33d7282a7afe401269b00f2a233a59c04b794a42901d862140b61d18d7c7f0ad5da040613e557f8abc74219",
|
||||
"2c060aaf",
|
||||
"99758aa7714fd707931f71803eefe04a06955041308a0b2a1104313b270ccf34",
|
||||
"63f690d8926408c7a34fe8ddd505a8dc58769dc74e8d5da6",
|
||||
"92b21ee85afcd8996ac28f3aed1047ad814d6e4ffbca3159af16f26eded83e4abda9e4275eb3ff0ad90dffe09f2d443b628f824f680b46527ce0128e8de1920f7c44350ebe7913",
|
||||
},
|
||||
{
|
||||
"f955183b1f762d4536d3f6885ea7f5ac27414caf46c2e24a2fd3bd56b91c53d840fb657224565e0a6f686f8ba320e04a401057399d9a3d995ab17c13",
|
||||
"c372ddc5",
|
||||
"a188be3795b2ca2e69b6aa263244f0963c492d694cf6c9b705a1d7045f3f2a26",
|
||||
"51bb484ea094ee140474681e1c838e4442fd148de2cc345a",
|
||||
"48759a5ddfdd829d11de8e0c538ce4a9c475faab6912039b568ad92d737d172fc1eb0c00c3793de6dddbfacfdbbc7f44aeba33684e18005aa982b6fc6c556e63bb90ff7a1dde8153a63eabe0",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"e013cd0bfafd486d",
|
||||
"af3d3ba094d38299ecb91c17bfe3d085da5bd42e11acf8acb5bc26a4be9a7583",
|
||||
"7dd63c14173831f109761b1c1abe18f6ba937d825957011b",
|
||||
"8bc685a7d9d501952295cd25d8c92517",
|
||||
},
|
||||
{
|
||||
"284b64597e",
|
||||
"31d013e53aa3ea79",
|
||||
"93c77409d7f805f97fe683b2dd6ee06152a5e918b3eed5b731acccffdcb2cc04",
|
||||
"3d331e90c4597cf0c30d1b7cfbd07bcb6ab927eda056873c",
|
||||
"3538a449d6c18d148a8c6cb76f1bc288657ac7036a",
|
||||
},
|
||||
{
|
||||
"9fe67f5c78180ede8274",
|
||||
"188608d230d75860",
|
||||
"b7cca89a82640aea6f80b458c9e633d88594fb498959d39787be87030892d48f",
|
||||
"ef891d50e8c08958f814590fdb7a9f16c61cc2aae1682109",
|
||||
"bbb40c30f3d1391a5b38df480cbbf964b71e763e8140751f4e28",
|
||||
},
|
||||
{
|
||||
"3a2826b6f7e3d542e4ded8f23c9aa4",
|
||||
"260033e789c4676a",
|
||||
"7fe2731214f2b4b42f93217d43f1776498413725e4f6cfe62b756e5a52df10ea",
|
||||
"888728219ebf761547f5e2218532714403020e5a8b7a49d0",
|
||||
"fe0328f883fcd88930ae017c0f54ed90f883041efc020e959125af370c1d47",
|
||||
},
|
||||
{
|
||||
"91858bf7b969005d7164acbd5678052b651c53e0",
|
||||
"f3cc53ecafcbadb3",
|
||||
"d69c04e9726b22d51f97bc9da0f0fda86736e6b78e8ef9f6f0000f79890d6d43",
|
||||
"6de3c45161b434e05445cf6bf69eef7bddf595fc6d8836bd",
|
||||
"a8869dd578c0835e120c843bb7dedc7a1e9eae24ffd742be6bf5b74088a8a2c550976fcb",
|
||||
},
|
||||
{
|
||||
"b3b1a4d6b2a2b9c5a1ca6c1efaec34dcfa1acbe7074d5e10cc",
|
||||
"d0f72bd16cda3bae",
|
||||
"2b317857b089c9305c49b83019f6e158bc4ecc3339b39ade02ee10c37c268da0",
|
||||
"cb5fa6d1e14a0b4bdf350cd10c8a7bd638102911ec74be09",
|
||||
"e6372f77c14343650074e07a2b7223c37b29242224b722b24d63b5956f27aa64ce7ce4e39cd14a2787",
|
||||
},
|
||||
{
|
||||
"057d3e9f865be7dff774938cab6d080e50cf9a1593f53c0063201e0bb7ae",
|
||||
"fd3881e505c8b12d",
|
||||
"36e42b1ef1ee8d068f09b5fad3ee43d98d34aa3e3f994f2055aee139da71de9d",
|
||||
"24124da36473d01bdca30297c9eef4fe61955525a453da17",
|
||||
"a8b28139524c98c1f8776f442eac4c22766fe6aac83224641c58bf021fc9cb709ec4706f49c2d0c1828acf2bfe8d",
|
||||
},
|
||||
{
|
||||
"bd8f13e928c34d67a6c70c3c7efdf2982ecc31d8cee68f9cbddc75912cd828ac93d28b",
|
||||
"193206c8fcc5b19b",
|
||||
"6e47c40c9d7b757c2efca4d73890e4c73f3c859aab4fdc64b564b8480dd84e72",
|
||||
"ca31340ae20d30fe488be355cb36652c5db7c9d6265a3e95",
|
||||
"a121efc5e1843deade4b8adbfef1808de4eda222f176630ad34fb476fca19e0299e4a13668e53cf13882035ba4f04f47c8b4e3",
|
||||
},
|
||||
{
|
||||
"23067a196e977d10039c14ff358061c918d2148d31961bb3e12c27c5122383cb25c4d1d79c775720",
|
||||
"62338d02fff78a00",
|
||||
"2c5c79c92d91fb40ef7d0a77e8033f7b265e3bab998b8116d17b2e62bb4f8a09",
|
||||
"024736adb1d5c01006dffd8158b57936d158d5b42054336d",
|
||||
"46d0905473a995d38c7cdbb8ef3da96ecc82a22c5b3c6c9d1c4a61ae7a17db53cb88c5f7eccf2da1d0c417c300f989b4273470e36f03542f",
|
||||
},
|
||||
{
|
||||
"252e966c680329eb687bff813b78fea3bfd3505333f106c6f9f45ba69896723c41bb763793d9b266e897d05557",
|
||||
"1e93e0cfe6523380",
|
||||
"9ec6fd1baa13ee16aec3fac16718a2baccf18a403cec467c25b7448e9b321110",
|
||||
"e7120b1018ab363a36e61102eedbcbe9847a6cbacaa9c328",
|
||||
"2934f034587d4144bb11182679cd2cd1c99c8088d18e233379e9bc9c41107a1f57a2723ecc7b9ba4e6ee198adf0fd766738e828827dc73136fc5b996e9",
|
||||
},
|
||||
{
|
||||
"6744aefcb318f12bc6eeb59d4d62f7eb95f347cea14bd5158415f07f84e4e3baa3de07512d9b76095ac1312cfcb1bb77f499",
|
||||
"608d2a33ce5d0b04",
|
||||
"0f665cbdaaa40f4f5a00c53d951b0a98aac2342be259a52670f650a783be7aab",
|
||||
"378bdb57e957b8c2e1500c9513052a3b02ff5b7edbd4a3a7",
|
||||
"341c60fcb374b394f1b01a4a80aedef49ab0b67ec963675e6eec43ef106f7003be87dbf4a8976709583dccc55abc7f979c4721837e8664a69804ea31736aa2af615a",
|
||||
},
|
||||
{
|
||||
"bcf1004f988220b7ce063ef2ec4e276ffd074f0a90aa807de1532679d2a1505568eaa4192d9a6ea52cc500322343ce9f8e68cc2c606d83",
|
||||
"e64bd00126c8792c",
|
||||
"58e65150d6a15dcefbc14a171998987ad0d709fb06a17d68d6a778759681c308",
|
||||
"106d2bd120b06e4eb10bc674fe55c77a3742225268319303",
|
||||
"a28052a6686a1e9435fee8702f7da563a7b3d7b5d3e9e27f11abf73db309cd1f39a34756258c1c5c7f2fb12cf15eb20175c2a08fc93dd19c5e482ef3fbef3d8404a3cfd54a7baf",
|
||||
},
|
||||
{
|
||||
"acd08d4938a224b4cb2d723bf75420f3ea27b698fadd815bb7db9548a05651398644354334e69f8e4e5503bf1a6f92b38e860044a7edca6874038ce1",
|
||||
"28a137808d0225b8",
|
||||
"a031203b963a395b08be55844d81af39d19b23b7cc24b21afa31edc1eea6edd6",
|
||||
"e8b31c52b6690f10f4ae62ba9d50ba39fb5edcfb78400e35",
|
||||
"35cf39ba31da95ac9b661cdbd5e9c9655d13b8ff065c4ec10c810833a47a87d8057dd1948a7801bfe6904b49fed0aabfb3cd755a1a262d372786908ddcf64cae9f71cb9ed199c3ddacc50116",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"cda7ee2857e09e9054ef6806",
|
||||
"d91dffb18132d8dd3d144a2f10ba28bc5df36cb60369f3b19893ec91db3cf904",
|
||||
"ee56f19c62b0438da6a0d9e01844313902be44f84a6a4ce7",
|
||||
"ccd48b61a5683c195d4424009eb1d147",
|
||||
},
|
||||
{
|
||||
"350f4c7ac2",
|
||||
"7c104b539c1d2ae022434cd6",
|
||||
"cbb61e369117f9250f68fa707240c554359262a4d66c757f80e3aeb6920894fb",
|
||||
"fbb14c9943444eac5413c6f5c8095451eddece02c9461043",
|
||||
"b5c6a35865ed8e5216ff6c77339ee1ab570de50e51",
|
||||
},
|
||||
{
|
||||
"4f0d61d3ea03a44a8df0",
|
||||
"51c20a8ae9e9794da931fe23",
|
||||
"ba6ced943aa62f9261d7513b822e02054e099acafb5360f0d850064da48b5a4f",
|
||||
"04c68cb50cdbb0ec03f8381cf59b886e64c40548bf8e3f82",
|
||||
"ea45a73957e2a853655623f2a3bb58791f7ea36dd2957ed66ffa",
|
||||
},
|
||||
{
|
||||
"4fbdd4d4293a8f34fdbc8f3ad44cf6",
|
||||
"8212f315e3759c3253c588bb",
|
||||
"5354791bc2370415811818e913e310dd12e6a0cf5dcab2b6424816eecccf4b65",
|
||||
"7ee6353c2fbc73c9ebc652270bc86e4008e09583e623e679",
|
||||
"50a354811a918e1801fb567621a8924baf8dd79da6d36702855d3753f1319c",
|
||||
},
|
||||
{
|
||||
"5a6f68b5a9a9920ca9c6edf5be7c0af150a063c4",
|
||||
"9a524aa62938fb7a1e50ed06",
|
||||
"fd91605a6ad85d8ba7a71b08dce1032aa9992bf4f28d407a53ddda04c043cada",
|
||||
"46791d99d6de33e79025bf9e97c198e7cf409614c6284b4d",
|
||||
"648033c1eb615467e90b7d3ac24202d8b849549141f9bab03e9e910c29b8eab3d4fb3f2c",
|
||||
},
|
||||
{
|
||||
"d9318c2c0d9ed89e35d242a6b1d496e7e0c5bbdf77eba14c56",
|
||||
"a16053c35fbe8dc93c14a81f",
|
||||
"f21406aec83134ebf7bc48c6d0f45acb5f341fbc7d3b5a9bff3ea1333c916af7",
|
||||
"de6b977be450d5efa7777e006802ddbb10814a22da1c3cd9",
|
||||
"8d3dad487d5161663da830b71c3e24ec5cdb74d858cbb73b084ed0902198532aad3a18416966bff223",
|
||||
},
|
||||
{
|
||||
"68d0ee08d38cb4bcc9268fee3030666e70e41fcabf6fe06536eeec43eec5",
|
||||
"11e09447d40b22dc98070eec",
|
||||
"da5ee1ec02eab13220fcb94f16efec848a8dd57c0f4d67955423f5d17fde5aa3",
|
||||
"8f13e61d773a250810f75d46bf163a3f9205be5751f6049a",
|
||||
"92a103b03764c1ad1f88500d22eeae5c0fe1044c872987c0b97affc5e8c3d783f8cc28a11dc91990ea22dd1bad74",
|
||||
},
|
||||
{
|
||||
"a1d960bda08efcf19e136dc1e8b05b6b381c820eda5f9a8047e1a2dd1803a1e4d11a7f",
|
||||
"aa73d8d4aaa0cfd9d80a9ae8",
|
||||
"08028833d617c28ba75b48f177cb5da87189189abb68dcb8974eca9230c25945",
|
||||
"f7b6f34a910fd11588f567de8555932291f7df05f6e2b193",
|
||||
"99cfc4cca193998bae153b744e6c94a82a2867780aa0f43acddb7c433fcb297311313ec2199f00d7ca7da0646b40113c60e935",
|
||||
},
|
||||
{
|
||||
"3b4ae39a745b6247ce5baf675ec36c5065b1bf76c8379eab4b769961d43a753896d068938017777e",
|
||||
"128c017a985052f8cdbc6b28",
|
||||
"4683d5caff613187a9b16af897253848e9c54fc0ec319de62452a86961d3cbb2",
|
||||
"5612a13c2da003b91188921cbac3fa093eba99d8cbbb51ff",
|
||||
"91a98b93b2174257175f7c882b45cc252e0db8667612bd270c1c12fe28b6bf209760bf8f370318f92ae3f88a5d4773b05714132cc28dddb8",
|
||||
},
|
||||
{
|
||||
"22ccf680d2995ef6563de281cff76882a036a59ad73f250e710b3040590d69bccde8a8411abe8b0d3cb728ca82",
|
||||
"13a97d0a167a61aa21e531ec",
|
||||
"9e140762eed274948b66de25e6e8f36ab65dc730b0cb096ef15aaba900a5588c",
|
||||
"d0e9594cfd42ab72553bf34062a263f588bb8f1fc86a19f5",
|
||||
"f194fc866dfba30e42c4508b7d90b3fa3f8983831ede713334563e36aa861f2f885b40be1dbe20ba2d10958a12823588d4bbbefb81a87d87315204f5e3",
|
||||
},
|
||||
{
|
||||
"a65f5d10c482b3381af296e631eb605eba6a11ccec6ceab021460d0bd35feb676ec6dbba5d4ad6c9f4d683ea541035bc80fa",
|
||||
"f15ae71ffed50a8fcc4996b0",
|
||||
"f535d60e8b75ac7e526041eed86eb4d65ae7e315eff15dba6c0133acc2a6a4bf",
|
||||
"01ba61691ebb3c66d2f94c1b1c597ecd7b5ff7d2a30be405",
|
||||
"d79e7c3893df5a5879c2f0a3f7ca619f08e4540f3ac7db35790b4211b9d47ae735adadf35fd47252a4763e3fd2b2cd8157f6ea7986108a53437962670a97d68ee281",
|
||||
},
|
||||
{
|
||||
"8c014655b97f6da76b0b168b565fd62de874c164fd7e227346a0ec22c908bed1e2a0b429620e6f3a68dd518f13a2c0250608a1cb08a7c3",
|
||||
"10a7eff999029c5040c1b3bd",
|
||||
"bf11af23e88c350a443493f6fa0eb34f234f4daa2676e26f0701bce5642d13f4",
|
||||
"f14c97392afd2e32e2c625910ca029f9b6e81676c79cc42f",
|
||||
"78d5226f372d5d60681dbfc749d12df74249f196b0cbf14fa65a3a59dc65ae458455ec39baa1df3397afe752bb06f6f13bf03c99abda7a95c1d0b73fd92d5f888a5f6f889a9aea",
|
||||
},
|
||||
{
|
||||
"66234d7a5b71eef134d60eccf7d5096ee879a33983d6f7a575e3a5e3a4022edccffe7865dde20b5b0a37252e31cb9a3650c63e35b057a1bc200a5b5b",
|
||||
"ccc2406f997bcae737ddd0f5",
|
||||
"d009eeb5b9b029577b14d200b7687b655eedb7d74add488f092681787999d66d",
|
||||
"99319712626b400f9458dbb7a9abc9f5810f25b47fc90b39",
|
||||
"543a2bbf52fd999027ae7c297353f3ce986f810bc2382583d0a81fda5939e4c87b6e8d262790cd614d6f753d8035b32adf43acc7f6d4c2c44289538928564b6587c2fcb99de1d8e34ffff323",
|
||||
},
|
||||
}
|
||||
|
67
vendor/golang.org/x/crypto/cryptobyte/asn1.go
generated
vendored
67
vendor/golang.org/x/crypto/cryptobyte/asn1.go
generated
vendored
@ -23,6 +23,12 @@ func (b *Builder) AddASN1Int64(v int64) {
|
||||
b.addASN1Signed(asn1.INTEGER, v)
|
||||
}
|
||||
|
||||
// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the
|
||||
// given tag.
|
||||
func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) {
|
||||
b.addASN1Signed(tag, v)
|
||||
}
|
||||
|
||||
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
|
||||
func (b *Builder) AddASN1Enum(v int64) {
|
||||
b.addASN1Signed(asn1.ENUM, v)
|
||||
@ -224,6 +230,9 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
|
||||
|
||||
// String
|
||||
|
||||
// ReadASN1Boolean decodes an ASN.1 INTEGER and converts it to a boolean
|
||||
// representation into out and advances. It reports whether the read
|
||||
// was successful.
|
||||
func (s *String) ReadASN1Boolean(out *bool) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 {
|
||||
@ -245,8 +254,8 @@ func (s *String) ReadASN1Boolean(out *bool) bool {
|
||||
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
|
||||
|
||||
// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
|
||||
// not point to an integer or to a big.Int, it panics. It returns true on
|
||||
// success and false on error.
|
||||
// not point to an integer or to a big.Int, it panics. It reports whether the
|
||||
// read was successful.
|
||||
func (s *String) ReadASN1Integer(out interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
@ -359,8 +368,16 @@ func asn1Unsigned(out *uint64, n []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns
|
||||
// true on success and false on error.
|
||||
// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out
|
||||
// and advances. It reports whether the read was successful and resulted in a
|
||||
// value that can be represented in an int64.
|
||||
func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool {
|
||||
var bytes String
|
||||
return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes)
|
||||
}
|
||||
|
||||
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadASN1Enum(out *int) bool {
|
||||
var bytes String
|
||||
var i int64
|
||||
@ -392,7 +409,7 @@ func (s *String) readBase128Int(out *int) bool {
|
||||
}
|
||||
|
||||
// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
|
||||
// advances. It returns true on success and false on error.
|
||||
// advances. It reports whether the read was successful.
|
||||
func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 {
|
||||
@ -431,7 +448,7 @@ func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) b
|
||||
}
|
||||
|
||||
// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
|
||||
// advances. It returns true on success and false on error.
|
||||
// advances. It reports whether the read was successful.
|
||||
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.GeneralizedTime) {
|
||||
@ -449,8 +466,8 @@ func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It
|
||||
// returns true on success and false on error.
|
||||
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
|
||||
@ -471,8 +488,8 @@ func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
|
||||
}
|
||||
|
||||
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is
|
||||
// an error if the BIT STRING is not a whole number of bytes. This function
|
||||
// returns true on success and false on error.
|
||||
// an error if the BIT STRING is not a whole number of bytes. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
|
||||
@ -489,14 +506,14 @@ func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
|
||||
|
||||
// ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
// given tag. It reports whether the read was successful.
|
||||
func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool {
|
||||
return s.ReadASN1((*String)(out), tag)
|
||||
}
|
||||
|
||||
// ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
// given tag. It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
|
||||
@ -509,7 +526,7 @@ func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
|
||||
|
||||
// ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
// given tag. It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
|
||||
@ -521,8 +538,8 @@ func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
|
||||
}
|
||||
|
||||
// ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, sets outTag to its tag, and advances. It
|
||||
// returns true on success and false on error.
|
||||
// tag and length bytes) into out, sets outTag to its tag, and advances.
|
||||
// It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
|
||||
@ -531,14 +548,14 @@ func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
|
||||
|
||||
// ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element
|
||||
// (including tag and length bytes) into out, sets outTag to is tag, and
|
||||
// advances. It returns true on success and false on error.
|
||||
// advances. It reports whether the read was successful.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool {
|
||||
return s.readASN1(out, outTag, false /* include header */)
|
||||
}
|
||||
|
||||
// PeekASN1Tag returns true if the next ASN.1 value on the string starts with
|
||||
// PeekASN1Tag reports whether the next ASN.1 value on the string starts with
|
||||
// the given tag.
|
||||
func (s String) PeekASN1Tag(tag asn1.Tag) bool {
|
||||
if len(s) == 0 {
|
||||
@ -547,7 +564,8 @@ func (s String) PeekASN1Tag(tag asn1.Tag) bool {
|
||||
return asn1.Tag(s[0]) == tag
|
||||
}
|
||||
|
||||
// SkipASN1 reads and discards an ASN.1 element with the given tag.
|
||||
// SkipASN1 reads and discards an ASN.1 element with the given tag. It
|
||||
// reports whether the operation was successful.
|
||||
func (s *String) SkipASN1(tag asn1.Tag) bool {
|
||||
var unused String
|
||||
return s.ReadASN1(&unused, tag)
|
||||
@ -556,7 +574,7 @@ func (s *String) SkipASN1(tag asn1.Tag) bool {
|
||||
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1
|
||||
// element (not including tag and length bytes) tagged with the given tag into
|
||||
// out. It stores whether an element with the tag was found in outPresent,
|
||||
// unless outPresent is nil. It returns true on success and false on error.
|
||||
// unless outPresent is nil. It reports whether the read was successful.
|
||||
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool {
|
||||
present := s.PeekASN1Tag(tag)
|
||||
if outPresent != nil {
|
||||
@ -569,7 +587,7 @@ func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) b
|
||||
}
|
||||
|
||||
// SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or
|
||||
// else leaves s unchanged.
|
||||
// else leaves s unchanged. It reports whether the operation was successful.
|
||||
func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
|
||||
if !s.PeekASN1Tag(tag) {
|
||||
return true
|
||||
@ -581,8 +599,8 @@ func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
|
||||
// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it writes defaultValue into out instead. If out
|
||||
// does not point to an integer or to a big.Int, it panics. It returns true on
|
||||
// success and false on error.
|
||||
// does not point to an integer or to a big.Int, it panics. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
@ -619,8 +637,8 @@ func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultV
|
||||
|
||||
// ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it writes defaultValue into out instead. It returns
|
||||
// true on success and false on error.
|
||||
// matching tag is present, it sets "out" to nil instead. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.Tag) bool {
|
||||
var present bool
|
||||
var child String
|
||||
@ -644,6 +662,7 @@ func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag
|
||||
|
||||
// ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or,
|
||||
// if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue.
|
||||
// It reports whether the operation was successful.
|
||||
func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool {
|
||||
var present bool
|
||||
var child String
|
||||
|
33
vendor/golang.org/x/crypto/cryptobyte/asn1_test.go
generated
vendored
33
vendor/golang.org/x/crypto/cryptobyte/asn1_test.go
generated
vendored
@ -149,6 +149,39 @@ func TestReadASN1IntegerSigned(t *testing.T) {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Repeat with the implicit-tagging functions
|
||||
t.Run("WithTag", func(t *testing.T) {
|
||||
for i, test := range testData64 {
|
||||
tag := asn1.Tag((i * 3) % 32).ContextSpecific()
|
||||
|
||||
testData := make([]byte, len(test.in))
|
||||
copy(testData, test.in)
|
||||
|
||||
// Alter the tag of the test case.
|
||||
testData[0] = uint8(tag)
|
||||
|
||||
in := String(testData)
|
||||
var out int64
|
||||
ok := in.ReadASN1Int64WithTag(&out, tag)
|
||||
if !ok || out != test.out {
|
||||
t.Errorf("#%d: in.ReadASN1Int64WithTag() = %v, want true; out = %d, want %d", i, ok, out, test.out)
|
||||
}
|
||||
|
||||
var b Builder
|
||||
b.AddASN1Int64WithTag(test.out, tag)
|
||||
result, err := b.Bytes()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("#%d: AddASN1Int64WithTag failed: %s", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(result, testData) {
|
||||
t.Errorf("#%d: AddASN1Int64WithTag: got %x, want %x", i, result, testData)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestReadASN1IntegerUnsigned(t *testing.T) {
|
||||
|
38
vendor/golang.org/x/crypto/cryptobyte/builder.go
generated
vendored
38
vendor/golang.org/x/crypto/cryptobyte/builder.go
generated
vendored
@ -50,8 +50,14 @@ func NewFixedBuilder(buffer []byte) *Builder {
|
||||
}
|
||||
}
|
||||
|
||||
// SetError sets the value to be returned as the error from Bytes. Writes
|
||||
// performed after calling SetError are ignored.
|
||||
func (b *Builder) SetError(err error) {
|
||||
b.err = err
|
||||
}
|
||||
|
||||
// Bytes returns the bytes written by the builder or an error if one has
|
||||
// occurred during during building.
|
||||
// occurred during building.
|
||||
func (b *Builder) Bytes() ([]byte, error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
@ -94,7 +100,7 @@ func (b *Builder) AddBytes(v []byte) {
|
||||
b.add(v...)
|
||||
}
|
||||
|
||||
// BuilderContinuation is continuation-passing interface for building
|
||||
// BuilderContinuation is a continuation-passing interface for building
|
||||
// length-prefixed byte sequences. Builder methods for length-prefixed
|
||||
// sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation
|
||||
// supplied to them. The child builder passed to the continuation can be used
|
||||
@ -268,9 +274,11 @@ func (b *Builder) flushChild() {
|
||||
return
|
||||
}
|
||||
|
||||
if !b.fixedSize {
|
||||
b.result = child.result // In case child reallocated result.
|
||||
if b.fixedSize && &b.result[0] != &child.result[0] {
|
||||
panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer")
|
||||
}
|
||||
|
||||
b.result = child.result
|
||||
}
|
||||
|
||||
func (b *Builder) add(bytes ...byte) {
|
||||
@ -278,7 +286,7 @@ func (b *Builder) add(bytes ...byte) {
|
||||
return
|
||||
}
|
||||
if b.child != nil {
|
||||
panic("attempted write while child is pending")
|
||||
panic("cryptobyte: attempted write while child is pending")
|
||||
}
|
||||
if len(b.result)+len(bytes) < len(bytes) {
|
||||
b.err = errors.New("cryptobyte: length overflow")
|
||||
@ -290,6 +298,26 @@ func (b *Builder) add(bytes ...byte) {
|
||||
b.result = append(b.result, bytes...)
|
||||
}
|
||||
|
||||
// Unwrite rolls back n bytes written directly to the Builder. An attempt by a
|
||||
// child builder passed to a continuation to unwrite bytes from its parent will
|
||||
// panic.
|
||||
func (b *Builder) Unwrite(n int) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
if b.child != nil {
|
||||
panic("cryptobyte: attempted unwrite while child is pending")
|
||||
}
|
||||
length := len(b.result) - b.pendingLenLen - b.offset
|
||||
if length < 0 {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
if n > length {
|
||||
panic("cryptobyte: attempted to unwrite more than was written")
|
||||
}
|
||||
b.result = b.result[:len(b.result)-n]
|
||||
}
|
||||
|
||||
// A MarshalingValue marshals itself into a Builder.
|
||||
type MarshalingValue interface {
|
||||
// Marshal is called by Builder.AddValue. It receives a pointer to a builder
|
||||
|
98
vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go
generated
vendored
98
vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go
generated
vendored
@ -327,12 +327,14 @@ func TestWriteWithPendingChild(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8LengthPrefixed(func(d *Builder) {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; c.AddUint8() did not panic")
|
||||
}
|
||||
func() {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; c.AddUint8() did not panic")
|
||||
}
|
||||
}()
|
||||
c.AddUint8(2) // panics
|
||||
}()
|
||||
c.AddUint8(2) // panics
|
||||
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
@ -351,6 +353,92 @@ func TestWriteWithPendingChild(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetError(t *testing.T) {
|
||||
const errorStr = "TestSetError"
|
||||
var b Builder
|
||||
b.SetError(errors.New(errorStr))
|
||||
|
||||
ret, err := b.Bytes()
|
||||
if ret != nil {
|
||||
t.Error("expected nil result")
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("unexpected nil error")
|
||||
}
|
||||
if s := err.Error(); s != errorStr {
|
||||
t.Errorf("expected error %q, got %v", errorStr, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnwrite(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
||||
b.Unwrite(2)
|
||||
if err := builderBytesEq(&b, 1, 2, 3); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
func() {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
|
||||
}
|
||||
}()
|
||||
b.Unwrite(4) // panics
|
||||
}()
|
||||
|
||||
b = Builder{}
|
||||
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
||||
b.AddUint8LengthPrefixed(func(b *Builder) {
|
||||
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
||||
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
|
||||
}
|
||||
}()
|
||||
b.Unwrite(6) // panics
|
||||
})
|
||||
|
||||
b = Builder{}
|
||||
b.AddBytes([]byte{1, 2, 3, 4, 5})
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; b.Unwrite() did not panic")
|
||||
}
|
||||
}()
|
||||
b.Unwrite(2) // panics (attempted unwrite while child is pending)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFixedBuilderLengthPrefixed(t *testing.T) {
|
||||
bufCap := 10
|
||||
inner := bytes.Repeat([]byte{0xff}, bufCap-2)
|
||||
buf := make([]byte, 0, bufCap)
|
||||
b := NewFixedBuilder(buf)
|
||||
b.AddUint16LengthPrefixed(func(b *Builder) {
|
||||
b.AddBytes(inner)
|
||||
})
|
||||
if got := b.BytesOrPanic(); len(got) != bufCap {
|
||||
t.Errorf("Expected output length to be %d, got %d", bufCap, len(got))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFixedBuilderPanicReallocate(t *testing.T) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
|
||||
b := NewFixedBuilder(make([]byte, 0, 10))
|
||||
b1 := NewFixedBuilder(make([]byte, 0, 10))
|
||||
b.AddUint16LengthPrefixed(func(b *Builder) {
|
||||
*b = *b1
|
||||
})
|
||||
|
||||
t.Error("Builder did not panic")
|
||||
}
|
||||
|
||||
// ASN.1
|
||||
|
||||
func TestASN1Int64(t *testing.T) {
|
||||
|
29
vendor/golang.org/x/crypto/cryptobyte/string.go
generated
vendored
29
vendor/golang.org/x/crypto/cryptobyte/string.go
generated
vendored
@ -37,8 +37,8 @@ func (s *String) Skip(n int) bool {
|
||||
return s.read(n) != nil
|
||||
}
|
||||
|
||||
// ReadUint8 decodes an 8-bit value into out and advances over it. It
|
||||
// returns true on success and false on error.
|
||||
// ReadUint8 decodes an 8-bit value into out and advances over it.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint8(out *uint8) bool {
|
||||
v := s.read(1)
|
||||
if v == nil {
|
||||
@ -49,7 +49,7 @@ func (s *String) ReadUint8(out *uint8) bool {
|
||||
}
|
||||
|
||||
// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint16(out *uint16) bool {
|
||||
v := s.read(2)
|
||||
if v == nil {
|
||||
@ -60,7 +60,7 @@ func (s *String) ReadUint16(out *uint16) bool {
|
||||
}
|
||||
|
||||
// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint24(out *uint32) bool {
|
||||
v := s.read(3)
|
||||
if v == nil {
|
||||
@ -71,7 +71,7 @@ func (s *String) ReadUint24(out *uint32) bool {
|
||||
}
|
||||
|
||||
// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
// It reports whether the read was successful.
|
||||
func (s *String) ReadUint32(out *uint32) bool {
|
||||
v := s.read(4)
|
||||
if v == nil {
|
||||
@ -119,28 +119,27 @@ func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
|
||||
}
|
||||
|
||||
// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
|
||||
// into out and advances over it. It returns true on success and false on
|
||||
// error.
|
||||
// into out and advances over it. It reports whether the read was successful.
|
||||
func (s *String) ReadUint8LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(1, out)
|
||||
}
|
||||
|
||||
// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
|
||||
// length-prefixed value into out and advances over it. It returns true on
|
||||
// success and false on error.
|
||||
// length-prefixed value into out and advances over it. It reports whether the
|
||||
// read was successful.
|
||||
func (s *String) ReadUint16LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(2, out)
|
||||
}
|
||||
|
||||
// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
|
||||
// length-prefixed value into out and advances over it. It returns true on
|
||||
// success and false on error.
|
||||
// length-prefixed value into out and advances over it. It reports whether
|
||||
// the read was successful.
|
||||
func (s *String) ReadUint24LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(3, out)
|
||||
}
|
||||
|
||||
// ReadBytes reads n bytes into out and advances over them. It returns true on
|
||||
// success and false and error.
|
||||
// ReadBytes reads n bytes into out and advances over them. It reports
|
||||
// whether the read was successful.
|
||||
func (s *String) ReadBytes(out *[]byte, n int) bool {
|
||||
v := s.read(n)
|
||||
if v == nil {
|
||||
@ -150,8 +149,8 @@ func (s *String) ReadBytes(out *[]byte, n int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// CopyBytes copies len(out) bytes into out and advances over them. It returns
|
||||
// true on success and false on error.
|
||||
// CopyBytes copies len(out) bytes into out and advances over them. It reports
|
||||
// whether the copy operation was successful
|
||||
func (s *String) CopyBytes(out []byte) bool {
|
||||
n := len(out)
|
||||
v := s.read(n)
|
||||
|
2
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
2
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
@ -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
|
||||
|
26
vendor/golang.org/x/crypto/curve25519/curve25519_test.go
generated
vendored
26
vendor/golang.org/x/crypto/curve25519/curve25519_test.go
generated
vendored
@ -5,6 +5,8 @@
|
||||
package curve25519
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
@ -28,6 +30,30 @@ func TestBaseScalarMult(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestHighBitIgnored tests the following requirement in RFC 7748:
|
||||
//
|
||||
// When receiving such an array, implementations of X25519 (but not X448) MUST
|
||||
// mask the most significant bit in the final byte.
|
||||
//
|
||||
// Regression test for issue #30095.
|
||||
func TestHighBitIgnored(t *testing.T) {
|
||||
var s, u [32]byte
|
||||
rand.Read(s[:])
|
||||
rand.Read(u[:])
|
||||
|
||||
var hi0, hi1 [32]byte
|
||||
|
||||
u[31] &= 0x7f
|
||||
ScalarMult(&hi0, &s, &u)
|
||||
|
||||
u[31] |= 0x80
|
||||
ScalarMult(&hi1, &s, &u)
|
||||
|
||||
if !bytes.Equal(hi0[:], hi1[:]) {
|
||||
t.Errorf("high bit of group point should not affect result")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScalarBaseMult(b *testing.B) {
|
||||
var in, out [32]byte
|
||||
in[0] = 1
|
||||
|
60
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
60
vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
@ -6,7 +6,10 @@
|
||||
// https://ed25519.cr.yp.to/.
|
||||
//
|
||||
// These functions are also compatible with the “Ed25519” function defined in
|
||||
// RFC 8032.
|
||||
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
|
||||
// representation includes a public key suffix to make multiple signing
|
||||
// operations with the same key more efficient. This package refers to the RFC
|
||||
// 8032 private key as the “seed”.
|
||||
package ed25519
|
||||
|
||||
// This code is a port of the public domain, “ref10” implementation of ed25519
|
||||
@ -31,6 +34,8 @@ const (
|
||||
PrivateKeySize = 64
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = 64
|
||||
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
|
||||
SeedSize = 32
|
||||
)
|
||||
|
||||
// PublicKey is the type of Ed25519 public keys.
|
||||
@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
|
||||
return PublicKey(publicKey)
|
||||
}
|
||||
|
||||
// Seed returns the private key seed corresponding to priv. It is provided for
|
||||
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
|
||||
// in this package.
|
||||
func (priv PrivateKey) Seed() []byte {
|
||||
seed := make([]byte, SeedSize)
|
||||
copy(seed, priv[:32])
|
||||
return seed
|
||||
}
|
||||
|
||||
// Sign signs the given message with priv.
|
||||
// Ed25519 performs two passes over messages to be signed and therefore cannot
|
||||
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
|
||||
@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
|
||||
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
|
||||
if rand == nil {
|
||||
rand = cryptorand.Reader
|
||||
}
|
||||
|
||||
privateKey = make([]byte, PrivateKeySize)
|
||||
publicKey = make([]byte, PublicKeySize)
|
||||
_, err = io.ReadFull(rand, privateKey[:32])
|
||||
if err != nil {
|
||||
seed := make([]byte, SeedSize)
|
||||
if _, err := io.ReadFull(rand, seed); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
digest := sha512.Sum512(privateKey[:32])
|
||||
privateKey := NewKeyFromSeed(seed)
|
||||
publicKey := make([]byte, PublicKeySize)
|
||||
copy(publicKey, privateKey[32:])
|
||||
|
||||
return publicKey, privateKey, nil
|
||||
}
|
||||
|
||||
// NewKeyFromSeed calculates a private key from a seed. It will panic if
|
||||
// len(seed) is not SeedSize. This function is provided for interoperability
|
||||
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
|
||||
// package.
|
||||
func NewKeyFromSeed(seed []byte) PrivateKey {
|
||||
if l := len(seed); l != SeedSize {
|
||||
panic("ed25519: bad seed length: " + strconv.Itoa(l))
|
||||
}
|
||||
|
||||
digest := sha512.Sum512(seed)
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
|
||||
var publicKeyBytes [32]byte
|
||||
A.ToBytes(&publicKeyBytes)
|
||||
|
||||
privateKey := make([]byte, PrivateKeySize)
|
||||
copy(privateKey, seed)
|
||||
copy(privateKey[32:], publicKeyBytes[:])
|
||||
copy(publicKey, publicKeyBytes[:])
|
||||
|
||||
return publicKey, privateKey, nil
|
||||
return privateKey
|
||||
}
|
||||
|
||||
// Sign signs the message with privateKey and returns a signature. It will
|
||||
@ -171,9 +200,16 @@ func Verify(publicKey PublicKey, message, sig []byte) bool {
|
||||
edwards25519.ScReduce(&hReduced, &digest)
|
||||
|
||||
var R edwards25519.ProjectiveGroupElement
|
||||
var b [32]byte
|
||||
copy(b[:], sig[32:])
|
||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
|
||||
var s [32]byte
|
||||
copy(s[:], sig[32:])
|
||||
|
||||
// https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in
|
||||
// the range [0, order) in order to prevent signature malleability.
|
||||
if !edwards25519.ScMinimal(&s) {
|
||||
return false
|
||||
}
|
||||
|
||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s)
|
||||
|
||||
var checkR [32]byte
|
||||
R.ToBytes(&checkR)
|
||||
|
37
vendor/golang.org/x/crypto/ed25519/ed25519_test.go
generated
vendored
37
vendor/golang.org/x/crypto/ed25519/ed25519_test.go
generated
vendored
@ -139,6 +139,19 @@ func TestGolden(t *testing.T) {
|
||||
if !Verify(pubKey, msg, sig2) {
|
||||
t.Errorf("signature failed to verify on line %d", lineNo)
|
||||
}
|
||||
|
||||
priv2 := NewKeyFromSeed(priv[:32])
|
||||
if !bytes.Equal(priv[:], priv2) {
|
||||
t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
|
||||
}
|
||||
|
||||
if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
|
||||
t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
|
||||
}
|
||||
|
||||
if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
|
||||
t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
@ -146,6 +159,30 @@ func TestGolden(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMalleability(t *testing.T) {
|
||||
// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
|
||||
// that s be in [0, order). This prevents someone from adding a multiple of
|
||||
// order to s and obtaining a second valid signature for the same message.
|
||||
msg := []byte{0x54, 0x65, 0x73, 0x74}
|
||||
sig := []byte{
|
||||
0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
|
||||
0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
|
||||
0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
|
||||
0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
|
||||
0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
|
||||
0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
|
||||
}
|
||||
publicKey := []byte{
|
||||
0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
|
||||
0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
|
||||
0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
|
||||
}
|
||||
|
||||
if Verify(publicKey, msg, sig) {
|
||||
t.Fatal("non-canonical signature accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeyGeneration(b *testing.B) {
|
||||
var zero zeroReader
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
22
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
22
vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
@ -4,6 +4,8 @@
|
||||
|
||||
package edwards25519
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// This code is a port of the public domain, “ref10” implementation of ed25519
|
||||
// from SUPERCOP.
|
||||
|
||||
@ -1769,3 +1771,23 @@ func ScReduce(out *[32]byte, s *[64]byte) {
|
||||
out[30] = byte(s11 >> 9)
|
||||
out[31] = byte(s11 >> 17)
|
||||
}
|
||||
|
||||
// order is the order of Curve25519 in little-endian form.
|
||||
var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000}
|
||||
|
||||
// ScMinimal returns true if the given scalar is less than the order of the
|
||||
// curve.
|
||||
func ScMinimal(scalar *[32]byte) bool {
|
||||
for i := 3; ; i-- {
|
||||
v := binary.LittleEndian.Uint64(scalar[i*8:])
|
||||
if v > order[i] {
|
||||
return false
|
||||
} else if v < order[i] {
|
||||
break
|
||||
} else if i == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
51
vendor/golang.org/x/crypto/hkdf/example_test.go
generated
vendored
51
vendor/golang.org/x/crypto/hkdf/example_test.go
generated
vendored
@ -9,49 +9,44 @@ import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// Usage example that expands one master key into three other cryptographically
|
||||
// secure keys.
|
||||
// Usage example that expands one master secret into three other
|
||||
// cryptographically secure keys.
|
||||
func Example_usage() {
|
||||
// Underlying hash function to use
|
||||
// Underlying hash function for HMAC.
|
||||
hash := sha256.New
|
||||
|
||||
// Cryptographically secure master key.
|
||||
master := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this.
|
||||
// Cryptographically secure master secret.
|
||||
secret := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this.
|
||||
|
||||
// Non secret salt, optional (can be nil)
|
||||
// Recommended: hash-length sized random
|
||||
// Non-secret salt, optional (can be nil).
|
||||
// Recommended: hash-length random value.
|
||||
salt := make([]byte, hash().Size())
|
||||
n, err := io.ReadFull(rand.Reader, salt)
|
||||
if n != len(salt) || err != nil {
|
||||
fmt.Println("error:", err)
|
||||
return
|
||||
if _, err := rand.Read(salt); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Non secret context specific info, optional (can be nil).
|
||||
// Note, independent from the master key.
|
||||
info := []byte{0x03, 0x14, 0x15, 0x92, 0x65}
|
||||
// Non-secret context info, optional (can be nil).
|
||||
info := []byte("hkdf example")
|
||||
|
||||
// Create the key derivation function
|
||||
hkdf := hkdf.New(hash, master, salt, info)
|
||||
// Generate three 128-bit derived keys.
|
||||
hkdf := hkdf.New(hash, secret, salt, info)
|
||||
|
||||
// Generate the required keys
|
||||
keys := make([][]byte, 3)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i] = make([]byte, 24)
|
||||
n, err := io.ReadFull(hkdf, keys[i])
|
||||
if n != len(keys[i]) || err != nil {
|
||||
fmt.Println("error:", err)
|
||||
return
|
||||
var keys [][]byte
|
||||
for i := 0; i < 3; i++ {
|
||||
key := make([]byte, 16)
|
||||
if _, err := io.ReadFull(hkdf, key); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
// Keys should contain 192 bit random keys
|
||||
for i := 1; i <= len(keys); i++ {
|
||||
fmt.Printf("Key #%d: %v\n", i, !bytes.Equal(keys[i-1], make([]byte, 24)))
|
||||
for i := range keys {
|
||||
fmt.Printf("Key #%d: %v\n", i+1, !bytes.Equal(keys[i], make([]byte, 16)))
|
||||
}
|
||||
|
||||
// Output:
|
||||
|
62
vendor/golang.org/x/crypto/hkdf/hkdf.go
generated
vendored
62
vendor/golang.org/x/crypto/hkdf/hkdf.go
generated
vendored
@ -8,8 +8,6 @@
|
||||
// HKDF is a cryptographic key derivation function (KDF) with the goal of
|
||||
// expanding limited input keying material into one or more cryptographically
|
||||
// strong secret keys.
|
||||
//
|
||||
// RFC 5869: https://tools.ietf.org/html/rfc5869
|
||||
package hkdf // import "golang.org/x/crypto/hkdf"
|
||||
|
||||
import (
|
||||
@ -19,6 +17,21 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Extract generates a pseudorandom key for use with Expand from an input secret
|
||||
// and an optional independent salt.
|
||||
//
|
||||
// Only use this function if you need to reuse the extracted key with multiple
|
||||
// Expand invocations and different context values. Most common scenarios,
|
||||
// including the generation of multiple keys, should use New instead.
|
||||
func Extract(hash func() hash.Hash, secret, salt []byte) []byte {
|
||||
if salt == nil {
|
||||
salt = make([]byte, hash().Size())
|
||||
}
|
||||
extractor := hmac.New(hash, salt)
|
||||
extractor.Write(secret)
|
||||
return extractor.Sum(nil)
|
||||
}
|
||||
|
||||
type hkdf struct {
|
||||
expander hash.Hash
|
||||
size int
|
||||
@ -26,22 +39,22 @@ type hkdf struct {
|
||||
info []byte
|
||||
counter byte
|
||||
|
||||
prev []byte
|
||||
cache []byte
|
||||
prev []byte
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func (f *hkdf) Read(p []byte) (int, error) {
|
||||
// Check whether enough data can be generated
|
||||
need := len(p)
|
||||
remains := len(f.cache) + int(255-f.counter+1)*f.size
|
||||
remains := len(f.buf) + int(255-f.counter+1)*f.size
|
||||
if remains < need {
|
||||
return 0, errors.New("hkdf: entropy limit reached")
|
||||
}
|
||||
// Read from the cache, if enough data is present
|
||||
n := copy(p, f.cache)
|
||||
// Read any leftover from the buffer
|
||||
n := copy(p, f.buf)
|
||||
p = p[n:]
|
||||
|
||||
// Fill the buffer
|
||||
// Fill the rest of the buffer
|
||||
for len(p) > 0 {
|
||||
f.expander.Reset()
|
||||
f.expander.Write(f.prev)
|
||||
@ -51,25 +64,30 @@ func (f *hkdf) Read(p []byte) (int, error) {
|
||||
f.counter++
|
||||
|
||||
// Copy the new batch into p
|
||||
f.cache = f.prev
|
||||
n = copy(p, f.cache)
|
||||
f.buf = f.prev
|
||||
n = copy(p, f.buf)
|
||||
p = p[n:]
|
||||
}
|
||||
// Save leftovers for next run
|
||||
f.cache = f.cache[n:]
|
||||
f.buf = f.buf[n:]
|
||||
|
||||
return need, nil
|
||||
}
|
||||
|
||||
// New returns a new HKDF using the given hash, the secret keying material to expand
|
||||
// and optional salt and info fields.
|
||||
func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
|
||||
if salt == nil {
|
||||
salt = make([]byte, hash().Size())
|
||||
}
|
||||
extractor := hmac.New(hash, salt)
|
||||
extractor.Write(secret)
|
||||
prk := extractor.Sum(nil)
|
||||
|
||||
return &hkdf{hmac.New(hash, prk), extractor.Size(), info, 1, nil, nil}
|
||||
// Expand returns a Reader, from which keys can be read, using the given
|
||||
// pseudorandom key and optional context info, skipping the extraction step.
|
||||
//
|
||||
// The pseudorandomKey should have been generated by Extract, or be a uniformly
|
||||
// random or pseudorandom cryptographically strong key. See RFC 5869, Section
|
||||
// 3.3. Most common scenarios will want to use New instead.
|
||||
func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader {
|
||||
expander := hmac.New(hash, pseudorandomKey)
|
||||
return &hkdf{expander, expander.Size(), info, 1, nil, nil}
|
||||
}
|
||||
|
||||
// New returns a Reader, from which keys can be read, using the given hash,
|
||||
// secret, salt and context info. Salt and info can be nil.
|
||||
func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
|
||||
prk := Extract(hash, secret, salt)
|
||||
return Expand(hash, prk, info)
|
||||
}
|
||||
|
81
vendor/golang.org/x/crypto/hkdf/hkdf_test.go
generated
vendored
81
vendor/golang.org/x/crypto/hkdf/hkdf_test.go
generated
vendored
@ -18,6 +18,7 @@ type hkdfTest struct {
|
||||
hash func() hash.Hash
|
||||
master []byte
|
||||
salt []byte
|
||||
prk []byte
|
||||
info []byte
|
||||
out []byte
|
||||
}
|
||||
@ -35,6 +36,12 @@ var hkdfTests = []hkdfTest{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c,
|
||||
},
|
||||
[]byte{
|
||||
0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
|
||||
0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
|
||||
0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
|
||||
0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5,
|
||||
},
|
||||
[]byte{
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9,
|
||||
@ -74,6 +81,12 @@ var hkdfTests = []hkdfTest{
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
},
|
||||
[]byte{
|
||||
0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a,
|
||||
0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c,
|
||||
0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01,
|
||||
0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44,
|
||||
},
|
||||
[]byte{
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
@ -108,6 +121,12 @@ var hkdfTests = []hkdfTest{
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
},
|
||||
[]byte{},
|
||||
[]byte{
|
||||
0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16,
|
||||
0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf,
|
||||
0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77,
|
||||
0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04,
|
||||
},
|
||||
[]byte{},
|
||||
[]byte{
|
||||
0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f,
|
||||
@ -118,6 +137,30 @@ var hkdfTests = []hkdfTest{
|
||||
0x96, 0xc8,
|
||||
},
|
||||
},
|
||||
{
|
||||
sha256.New,
|
||||
[]byte{
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
},
|
||||
nil,
|
||||
[]byte{
|
||||
0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16,
|
||||
0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf,
|
||||
0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77,
|
||||
0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04,
|
||||
},
|
||||
nil,
|
||||
[]byte{
|
||||
0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f,
|
||||
0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31,
|
||||
0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e,
|
||||
0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d,
|
||||
0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a,
|
||||
0x96, 0xc8,
|
||||
},
|
||||
},
|
||||
{
|
||||
sha1.New,
|
||||
[]byte{
|
||||
@ -128,6 +171,11 @@ var hkdfTests = []hkdfTest{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c,
|
||||
},
|
||||
[]byte{
|
||||
0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f,
|
||||
0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b,
|
||||
0xaa, 0x2b, 0xa2, 0x43,
|
||||
},
|
||||
[]byte{
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9,
|
||||
@ -167,6 +215,11 @@ var hkdfTests = []hkdfTest{
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
},
|
||||
[]byte{
|
||||
0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59,
|
||||
0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a,
|
||||
0x22, 0x4c, 0xfa, 0xf6,
|
||||
},
|
||||
[]byte{
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
@ -201,6 +254,11 @@ var hkdfTests = []hkdfTest{
|
||||
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
||||
},
|
||||
[]byte{},
|
||||
[]byte{
|
||||
0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28,
|
||||
0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a,
|
||||
0xa0, 0xd3, 0x2d, 0x01,
|
||||
},
|
||||
[]byte{},
|
||||
[]byte{
|
||||
0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61,
|
||||
@ -219,7 +277,12 @@ var hkdfTests = []hkdfTest{
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
},
|
||||
nil,
|
||||
[]byte{},
|
||||
[]byte{
|
||||
0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c,
|
||||
0x20, 0x77, 0xad, 0x2e, 0xb1, 0x9d, 0x3f, 0x3e,
|
||||
0x73, 0x13, 0x85, 0xdd,
|
||||
},
|
||||
nil,
|
||||
[]byte{
|
||||
0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3,
|
||||
0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a,
|
||||
@ -233,6 +296,11 @@ var hkdfTests = []hkdfTest{
|
||||
|
||||
func TestHKDF(t *testing.T) {
|
||||
for i, tt := range hkdfTests {
|
||||
prk := Extract(tt.hash, tt.master, tt.salt)
|
||||
if !bytes.Equal(prk, tt.prk) {
|
||||
t.Errorf("test %d: incorrect PRK: have %v, need %v.", i, prk, tt.prk)
|
||||
}
|
||||
|
||||
hkdf := New(tt.hash, tt.master, tt.salt, tt.info)
|
||||
out := make([]byte, len(tt.out))
|
||||
|
||||
@ -244,6 +312,17 @@ func TestHKDF(t *testing.T) {
|
||||
if !bytes.Equal(out, tt.out) {
|
||||
t.Errorf("test %d: incorrect output: have %v, need %v.", i, out, tt.out)
|
||||
}
|
||||
|
||||
hkdf = Expand(tt.hash, prk, tt.info)
|
||||
|
||||
n, err = io.ReadFull(hkdf, out)
|
||||
if n != len(tt.out) || err != nil {
|
||||
t.Errorf("test %d: not enough output bytes from Expand: %d.", i, n)
|
||||
}
|
||||
|
||||
if !bytes.Equal(out, tt.out) {
|
||||
t.Errorf("test %d: incorrect output from Expand: have %v, need %v.", i, out, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
420
vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
generated
vendored
420
vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go
generated
vendored
@ -2,197 +2,263 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ChaCha20 implements the core ChaCha20 function as specified in https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
// Package ChaCha20 implements the core ChaCha20 function as specified
|
||||
// in https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
package chacha20
|
||||
|
||||
import "encoding/binary"
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
|
||||
const rounds = 20
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
)
|
||||
|
||||
// core applies the ChaCha20 core function to 16-byte input in, 32-byte key k,
|
||||
// and 16-byte constant c, and puts the result into 64-byte array out.
|
||||
func core(out *[64]byte, in *[16]byte, k *[32]byte) {
|
||||
j0 := uint32(0x61707865)
|
||||
j1 := uint32(0x3320646e)
|
||||
j2 := uint32(0x79622d32)
|
||||
j3 := uint32(0x6b206574)
|
||||
j4 := binary.LittleEndian.Uint32(k[0:4])
|
||||
j5 := binary.LittleEndian.Uint32(k[4:8])
|
||||
j6 := binary.LittleEndian.Uint32(k[8:12])
|
||||
j7 := binary.LittleEndian.Uint32(k[12:16])
|
||||
j8 := binary.LittleEndian.Uint32(k[16:20])
|
||||
j9 := binary.LittleEndian.Uint32(k[20:24])
|
||||
j10 := binary.LittleEndian.Uint32(k[24:28])
|
||||
j11 := binary.LittleEndian.Uint32(k[28:32])
|
||||
j12 := binary.LittleEndian.Uint32(in[0:4])
|
||||
j13 := binary.LittleEndian.Uint32(in[4:8])
|
||||
j14 := binary.LittleEndian.Uint32(in[8:12])
|
||||
j15 := binary.LittleEndian.Uint32(in[12:16])
|
||||
// assert that *Cipher implements cipher.Stream
|
||||
var _ cipher.Stream = (*Cipher)(nil)
|
||||
|
||||
x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7
|
||||
x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15
|
||||
// Cipher is a stateful instance of ChaCha20 using a particular key
|
||||
// and nonce. A *Cipher implements the cipher.Stream interface.
|
||||
type Cipher struct {
|
||||
key [8]uint32
|
||||
counter uint32 // incremented after each block
|
||||
nonce [3]uint32
|
||||
buf [bufSize]byte // buffer for unused keystream bytes
|
||||
len int // number of unused keystream bytes at end of buf
|
||||
}
|
||||
|
||||
for i := 0; i < rounds; i += 2 {
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 16) | (x12 >> (16))
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 12) | (x4 >> (20))
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 8) | (x12 >> (24))
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 7) | (x4 >> (25))
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 16) | (x12 >> 16)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 8) | (x12 >> 24)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 12) | (x4 >> 20)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 7) | (x4 >> 25)
|
||||
// New creates a new ChaCha20 stream cipher with the given key and nonce.
|
||||
// The initial counter value is set to 0.
|
||||
func New(key [8]uint32, nonce [3]uint32) *Cipher {
|
||||
return &Cipher{key: key, nonce: nonce}
|
||||
}
|
||||
|
||||
// ChaCha20 constants spelling "expand 32-byte k"
|
||||
const (
|
||||
j0 uint32 = 0x61707865
|
||||
j1 uint32 = 0x3320646e
|
||||
j2 uint32 = 0x79622d32
|
||||
j3 uint32 = 0x6b206574
|
||||
)
|
||||
|
||||
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
|
||||
a += b
|
||||
d ^= a
|
||||
d = (d << 16) | (d >> 16)
|
||||
c += d
|
||||
b ^= c
|
||||
b = (b << 12) | (b >> 20)
|
||||
a += b
|
||||
d ^= a
|
||||
d = (d << 8) | (d >> 24)
|
||||
c += d
|
||||
b ^= c
|
||||
b = (b << 7) | (b >> 25)
|
||||
return a, b, c, d
|
||||
}
|
||||
|
||||
// XORKeyStream XORs each byte in the given slice with a byte from the
|
||||
// cipher's key stream. Dst and src must overlap entirely or not at all.
|
||||
//
|
||||
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
|
||||
// to pass a dst bigger than src, and in that case, XORKeyStream will
|
||||
// only update dst[:len(src)] and will not touch the rest of dst.
|
||||
//
|
||||
// Multiple calls to XORKeyStream behave as if the concatenation of
|
||||
// the src buffers was passed in a single run. That is, Cipher
|
||||
// maintains state and does not reset at each XORKeyStream call.
|
||||
func (s *Cipher) XORKeyStream(dst, src []byte) {
|
||||
if len(dst) < len(src) {
|
||||
panic("chacha20: output smaller than input")
|
||||
}
|
||||
if subtle.InexactOverlap(dst[:len(src)], src) {
|
||||
panic("chacha20: invalid buffer overlap")
|
||||
}
|
||||
|
||||
x0 += j0
|
||||
x1 += j1
|
||||
x2 += j2
|
||||
x3 += j3
|
||||
x4 += j4
|
||||
x5 += j5
|
||||
x6 += j6
|
||||
x7 += j7
|
||||
x8 += j8
|
||||
x9 += j9
|
||||
x10 += j10
|
||||
x11 += j11
|
||||
x12 += j12
|
||||
x13 += j13
|
||||
x14 += j14
|
||||
x15 += j15
|
||||
// xor src with buffered keystream first
|
||||
if s.len != 0 {
|
||||
buf := s.buf[len(s.buf)-s.len:]
|
||||
if len(src) < len(buf) {
|
||||
buf = buf[:len(src)]
|
||||
}
|
||||
td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
|
||||
for i, b := range buf {
|
||||
td[i] = ts[i] ^ b
|
||||
}
|
||||
s.len -= len(buf)
|
||||
if s.len != 0 {
|
||||
return
|
||||
}
|
||||
s.buf = [len(s.buf)]byte{} // zero the empty buffer
|
||||
src = src[len(buf):]
|
||||
dst = dst[len(buf):]
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||
binary.LittleEndian.PutUint32(out[16:20], x4)
|
||||
binary.LittleEndian.PutUint32(out[20:24], x5)
|
||||
binary.LittleEndian.PutUint32(out[24:28], x6)
|
||||
binary.LittleEndian.PutUint32(out[28:32], x7)
|
||||
binary.LittleEndian.PutUint32(out[32:36], x8)
|
||||
binary.LittleEndian.PutUint32(out[36:40], x9)
|
||||
binary.LittleEndian.PutUint32(out[40:44], x10)
|
||||
binary.LittleEndian.PutUint32(out[44:48], x11)
|
||||
binary.LittleEndian.PutUint32(out[48:52], x12)
|
||||
binary.LittleEndian.PutUint32(out[52:56], x13)
|
||||
binary.LittleEndian.PutUint32(out[56:60], x14)
|
||||
binary.LittleEndian.PutUint32(out[60:64], x15)
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
if haveAsm {
|
||||
if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
|
||||
panic("chacha20: counter overflow")
|
||||
}
|
||||
s.xorKeyStreamAsm(dst, src)
|
||||
return
|
||||
}
|
||||
|
||||
// set up a 64-byte buffer to pad out the final block if needed
|
||||
// (hoisted out of the main loop to avoid spills)
|
||||
rem := len(src) % 64 // length of final block
|
||||
fin := len(src) - rem // index of final block
|
||||
if rem > 0 {
|
||||
copy(s.buf[len(s.buf)-64:], src[fin:])
|
||||
}
|
||||
|
||||
// pre-calculate most of the first round
|
||||
s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
|
||||
s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
|
||||
s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
|
||||
|
||||
n := len(src)
|
||||
src, dst = src[:n:n], dst[:n:n] // BCE hint
|
||||
for i := 0; i < n; i += 64 {
|
||||
// calculate the remainder of the first round
|
||||
s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
|
||||
|
||||
// execute the second round
|
||||
x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
|
||||
x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
|
||||
x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
|
||||
x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
|
||||
|
||||
// execute the remaining 18 rounds
|
||||
for i := 0; i < 9; i++ {
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
||||
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
x0 += j0
|
||||
x1 += j1
|
||||
x2 += j2
|
||||
x3 += j3
|
||||
|
||||
x4 += s.key[0]
|
||||
x5 += s.key[1]
|
||||
x6 += s.key[2]
|
||||
x7 += s.key[3]
|
||||
x8 += s.key[4]
|
||||
x9 += s.key[5]
|
||||
x10 += s.key[6]
|
||||
x11 += s.key[7]
|
||||
|
||||
x12 += s.counter
|
||||
x13 += s.nonce[0]
|
||||
x14 += s.nonce[1]
|
||||
x15 += s.nonce[2]
|
||||
|
||||
// increment the counter
|
||||
s.counter += 1
|
||||
if s.counter == 0 {
|
||||
panic("chacha20: counter overflow")
|
||||
}
|
||||
|
||||
// pad to 64 bytes if needed
|
||||
in, out := src[i:], dst[i:]
|
||||
if i == fin {
|
||||
// src[fin:] has already been copied into s.buf before
|
||||
// the main loop
|
||||
in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
|
||||
}
|
||||
in, out = in[:64], out[:64] // BCE hint
|
||||
|
||||
// XOR the key stream with the source and write out the result
|
||||
xor(out[0:], in[0:], x0)
|
||||
xor(out[4:], in[4:], x1)
|
||||
xor(out[8:], in[8:], x2)
|
||||
xor(out[12:], in[12:], x3)
|
||||
xor(out[16:], in[16:], x4)
|
||||
xor(out[20:], in[20:], x5)
|
||||
xor(out[24:], in[24:], x6)
|
||||
xor(out[28:], in[28:], x7)
|
||||
xor(out[32:], in[32:], x8)
|
||||
xor(out[36:], in[36:], x9)
|
||||
xor(out[40:], in[40:], x10)
|
||||
xor(out[44:], in[44:], x11)
|
||||
xor(out[48:], in[48:], x12)
|
||||
xor(out[52:], in[52:], x13)
|
||||
xor(out[56:], in[56:], x14)
|
||||
xor(out[60:], in[60:], x15)
|
||||
}
|
||||
// copy any trailing bytes out of the buffer and into dst
|
||||
if rem != 0 {
|
||||
s.len = 64 - rem
|
||||
copy(dst[fin:], s.buf[len(s.buf)-64:])
|
||||
}
|
||||
}
|
||||
|
||||
// Advance discards bytes in the key stream until the next 64 byte block
|
||||
// boundary is reached and updates the counter accordingly. If the key
|
||||
// stream is already at a block boundary no bytes will be discarded and
|
||||
// the counter will be unchanged.
|
||||
func (s *Cipher) Advance() {
|
||||
s.len -= s.len % 64
|
||||
if s.len == 0 {
|
||||
s.buf = [len(s.buf)]byte{}
|
||||
}
|
||||
}
|
||||
|
||||
// XORKeyStream crypts bytes from in to out using the given key and counters.
|
||||
// In and out must overlap entirely or not at all. Counter contains the raw
|
||||
// ChaCha20 counter bytes (i.e. block counter followed by nonce).
|
||||
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
|
||||
var block [64]byte
|
||||
var counterCopy [16]byte
|
||||
copy(counterCopy[:], counter[:])
|
||||
|
||||
for len(in) >= 64 {
|
||||
core(&block, &counterCopy, key)
|
||||
for i, x := range block {
|
||||
out[i] = in[i] ^ x
|
||||
}
|
||||
u := uint32(1)
|
||||
for i := 0; i < 4; i++ {
|
||||
u += uint32(counterCopy[i])
|
||||
counterCopy[i] = byte(u)
|
||||
u >>= 8
|
||||
}
|
||||
in = in[64:]
|
||||
out = out[64:]
|
||||
}
|
||||
|
||||
if len(in) > 0 {
|
||||
core(&block, &counterCopy, key)
|
||||
for i, v := range in {
|
||||
out[i] = v ^ block[i]
|
||||
}
|
||||
s := Cipher{
|
||||
key: [8]uint32{
|
||||
binary.LittleEndian.Uint32(key[0:4]),
|
||||
binary.LittleEndian.Uint32(key[4:8]),
|
||||
binary.LittleEndian.Uint32(key[8:12]),
|
||||
binary.LittleEndian.Uint32(key[12:16]),
|
||||
binary.LittleEndian.Uint32(key[16:20]),
|
||||
binary.LittleEndian.Uint32(key[20:24]),
|
||||
binary.LittleEndian.Uint32(key[24:28]),
|
||||
binary.LittleEndian.Uint32(key[28:32]),
|
||||
},
|
||||
nonce: [3]uint32{
|
||||
binary.LittleEndian.Uint32(counter[4:8]),
|
||||
binary.LittleEndian.Uint32(counter[8:12]),
|
||||
binary.LittleEndian.Uint32(counter[12:16]),
|
||||
},
|
||||
counter: binary.LittleEndian.Uint32(counter[0:4]),
|
||||
}
|
||||
s.XORKeyStream(out, in)
|
||||
}
|
||||
|
||||
// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
|
||||
// nonce. It should only be used as part of the XChaCha20 construction.
|
||||
func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
|
||||
x0, x1, x2, x3 := j0, j1, j2, j3
|
||||
x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
|
||||
x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
|
||||
x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
|
||||
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
|
||||
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
|
||||
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
|
||||
|
||||
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
|
||||
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
|
||||
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
|
||||
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
var out [8]uint32
|
||||
out[0], out[1], out[2], out[3] = x0, x1, x2, x3
|
||||
out[4], out[5], out[6], out[7] = x12, x13, x14, x15
|
||||
return out
|
||||
}
|
||||
|
192
vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go
generated
vendored
192
vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go
generated
vendored
@ -5,7 +5,10 @@
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -31,3 +34,192 @@ func TestCore(t *testing.T) {
|
||||
t.Errorf("wanted %x but got %x", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test cases with the input and output in different buffers.
|
||||
func TestNoOverlap(t *testing.T) {
|
||||
for _, c := range testVectors {
|
||||
s := New(c.key, c.nonce)
|
||||
input, err := hex.DecodeString(c.input)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot decode input %#v: %v", c.input, err)
|
||||
}
|
||||
output := make([]byte, c.length)
|
||||
s.XORKeyStream(output, input)
|
||||
got := hex.EncodeToString(output)
|
||||
if got != c.output {
|
||||
t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test cases with the input and output overlapping entirely.
|
||||
func TestOverlap(t *testing.T) {
|
||||
for _, c := range testVectors {
|
||||
s := New(c.key, c.nonce)
|
||||
data, err := hex.DecodeString(c.input)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot decode input %#v: %v", c.input, err)
|
||||
}
|
||||
s.XORKeyStream(data, data)
|
||||
got := hex.EncodeToString(data)
|
||||
if got != c.output {
|
||||
t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test cases with various source and destination offsets.
|
||||
func TestUnaligned(t *testing.T) {
|
||||
const max = 8 // max offset (+1) to test
|
||||
for _, c := range testVectors {
|
||||
input := make([]byte, c.length+max)
|
||||
output := make([]byte, c.length+max)
|
||||
for i := 0; i < max; i++ { // input offsets
|
||||
for j := 0; j < max; j++ { // output offsets
|
||||
s := New(c.key, c.nonce)
|
||||
|
||||
input := input[i : i+c.length]
|
||||
output := output[j : j+c.length]
|
||||
|
||||
data, err := hex.DecodeString(c.input)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot decode input %#v: %v", c.input, err)
|
||||
}
|
||||
copy(input, data)
|
||||
s.XORKeyStream(output, input)
|
||||
got := hex.EncodeToString(output)
|
||||
if got != c.output {
|
||||
t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test cases by calling XORKeyStream multiple times.
|
||||
func TestStep(t *testing.T) {
|
||||
// wide range of step sizes to try and hit edge cases
|
||||
steps := [...]int{1, 3, 4, 7, 8, 17, 24, 30, 64, 256}
|
||||
rnd := rand.New(rand.NewSource(123))
|
||||
for _, c := range testVectors {
|
||||
s := New(c.key, c.nonce)
|
||||
input, err := hex.DecodeString(c.input)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot decode input %#v: %v", c.input, err)
|
||||
}
|
||||
output := make([]byte, c.length)
|
||||
|
||||
// step through the buffers
|
||||
i, step := 0, steps[rnd.Intn(len(steps))]
|
||||
for i+step < c.length {
|
||||
s.XORKeyStream(output[i:i+step], input[i:i+step])
|
||||
if i+step < c.length && output[i+step] != 0 {
|
||||
t.Errorf("length=%v, i=%v, step=%v: output overwritten", c.length, i, step)
|
||||
}
|
||||
i += step
|
||||
step = steps[rnd.Intn(len(steps))]
|
||||
}
|
||||
// finish the encryption
|
||||
s.XORKeyStream(output[i:], input[i:])
|
||||
|
||||
got := hex.EncodeToString(output)
|
||||
if got != c.output {
|
||||
t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Advance() discards bytes until a block boundary is hit.
|
||||
func TestAdvance(t *testing.T) {
|
||||
for _, c := range testVectors {
|
||||
for i := 0; i < 63; i++ {
|
||||
s := New(c.key, c.nonce)
|
||||
z := New(c.key, c.nonce)
|
||||
input, err := hex.DecodeString(c.input)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot decode input %#v: %v", c.input, err)
|
||||
}
|
||||
zeros, discard := make([]byte, 64), make([]byte, 64)
|
||||
so, zo := make([]byte, c.length), make([]byte, c.length)
|
||||
for j := 0; j < c.length; j += 64 {
|
||||
lim := j + i
|
||||
if lim > c.length {
|
||||
lim = c.length
|
||||
}
|
||||
s.XORKeyStream(so[j:lim], input[j:lim])
|
||||
// calling s.Advance() multiple times should have no effect
|
||||
for k := 0; k < i%3+1; k++ {
|
||||
s.Advance()
|
||||
}
|
||||
z.XORKeyStream(zo[j:lim], input[j:lim])
|
||||
if lim < c.length {
|
||||
end := 64 - i
|
||||
if c.length-lim < end {
|
||||
end = c.length - lim
|
||||
}
|
||||
z.XORKeyStream(discard[:], zeros[:end])
|
||||
}
|
||||
}
|
||||
|
||||
got := hex.EncodeToString(so)
|
||||
want := hex.EncodeToString(zo)
|
||||
if got != want {
|
||||
t.Errorf("length=%v: got %#v, want %#v", c.length, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChaCha20(b *testing.B) {
|
||||
sizes := []int{32, 63, 64, 256, 1024, 1350, 65536}
|
||||
for _, size := range sizes {
|
||||
s := size
|
||||
b.Run(fmt.Sprint(s), func(b *testing.B) {
|
||||
k := [32]byte{}
|
||||
c := [16]byte{}
|
||||
src := make([]byte, s)
|
||||
dst := make([]byte, s)
|
||||
b.SetBytes(int64(s))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
XORKeyStream(dst, src, &c, &k)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHChaCha20(t *testing.T) {
|
||||
// See draft-paragon-paseto-rfc-00 §7.2.1.
|
||||
key := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}
|
||||
nonce := []byte{0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a,
|
||||
0x00, 0x00, 0x00, 0x00, 0x31, 0x41, 0x59, 0x27}
|
||||
expected := []byte{0x82, 0x41, 0x3b, 0x42, 0x27, 0xb2, 0x7b, 0xfe,
|
||||
0xd3, 0x0e, 0x42, 0x50, 0x8a, 0x87, 0x7d, 0x73,
|
||||
0xa0, 0xf9, 0xe4, 0xd5, 0x8a, 0x74, 0xa8, 0x53,
|
||||
0xc1, 0x2e, 0xc4, 0x13, 0x26, 0xd3, 0xec, 0xdc,
|
||||
}
|
||||
result := HChaCha20(&[8]uint32{
|
||||
binary.LittleEndian.Uint32(key[0:4]),
|
||||
binary.LittleEndian.Uint32(key[4:8]),
|
||||
binary.LittleEndian.Uint32(key[8:12]),
|
||||
binary.LittleEndian.Uint32(key[12:16]),
|
||||
binary.LittleEndian.Uint32(key[16:20]),
|
||||
binary.LittleEndian.Uint32(key[20:24]),
|
||||
binary.LittleEndian.Uint32(key[24:28]),
|
||||
binary.LittleEndian.Uint32(key[28:32]),
|
||||
}, &[4]uint32{
|
||||
binary.LittleEndian.Uint32(nonce[0:4]),
|
||||
binary.LittleEndian.Uint32(nonce[4:8]),
|
||||
binary.LittleEndian.Uint32(nonce[8:12]),
|
||||
binary.LittleEndian.Uint32(nonce[12:16]),
|
||||
})
|
||||
for i := 0; i < 8; i++ {
|
||||
want := binary.LittleEndian.Uint32(expected[i*4 : (i+1)*4])
|
||||
if got := result[i]; got != want {
|
||||
t.Errorf("word %d incorrect: want 0x%x, got 0x%x", i, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
4
vendor/golang.org/x/crypto/md4/md4.go
generated
vendored
4
vendor/golang.org/x/crypto/md4/md4.go
generated
vendored
@ -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 (
|
||||
|
9
vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go
generated
vendored
9
vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go
generated
vendored
@ -35,6 +35,7 @@ This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html.
|
||||
package secretbox // import "golang.org/x/crypto/nacl/secretbox"
|
||||
|
||||
import (
|
||||
"golang.org/x/crypto/internal/subtle"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
"golang.org/x/crypto/salsa20/salsa"
|
||||
)
|
||||
@ -87,6 +88,9 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
|
||||
copy(poly1305Key[:], firstBlock[:])
|
||||
|
||||
ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
|
||||
if subtle.AnyOverlap(out, message) {
|
||||
panic("nacl: invalid buffer overlap")
|
||||
}
|
||||
|
||||
// We XOR up to 32 bytes of message with the keystream generated from
|
||||
// the first block.
|
||||
@ -118,7 +122,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
|
||||
// Open authenticates and decrypts a box produced by Seal and appends the
|
||||
// message to out, which must not overlap box. The output will be Overhead
|
||||
// bytes smaller than box.
|
||||
func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
|
||||
func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
|
||||
if len(box) < Overhead {
|
||||
return nil, false
|
||||
}
|
||||
@ -143,6 +147,9 @@ func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool)
|
||||
}
|
||||
|
||||
ret, out := sliceForAppend(out, len(box)-Overhead)
|
||||
if subtle.AnyOverlap(out, box) {
|
||||
panic("nacl: invalid buffer overlap")
|
||||
}
|
||||
|
||||
// We XOR up to 32 bytes of box with the keystream generated from
|
||||
// the first block.
|
||||
|
14
vendor/golang.org/x/crypto/ocsp/ocsp.go
generated
vendored
14
vendor/golang.org/x/crypto/ocsp/ocsp.go
generated
vendored
@ -63,7 +63,7 @@ func (r ResponseStatus) String() string {
|
||||
}
|
||||
|
||||
// ResponseError is an error that may be returned by ParseResponse to indicate
|
||||
// that the response itself is an error, not just that its indicating that a
|
||||
// that the response itself is an error, not just that it's indicating that a
|
||||
// certificate is revoked, unknown, etc.
|
||||
type ResponseError struct {
|
||||
Status ResponseStatus
|
||||
@ -487,9 +487,8 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(basicResp.Certificates) > 1 {
|
||||
return nil, ParseError("OCSP response contains bad number of certificates")
|
||||
if len(rest) > 0 {
|
||||
return nil, ParseError("trailing data in OCSP response")
|
||||
}
|
||||
|
||||
if n := len(basicResp.TBSResponseData.Responses); n == 0 || cert == nil && n > 1 {
|
||||
@ -544,6 +543,13 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
|
||||
}
|
||||
|
||||
if len(basicResp.Certificates) > 0 {
|
||||
// Responders should only send a single certificate (if they
|
||||
// send any) that connects the responder's certificate to the
|
||||
// original issuer. We accept responses with multiple
|
||||
// certificates due to a number responders sending them[1], but
|
||||
// ignore all but the first.
|
||||
//
|
||||
// [1] https://github.com/golang/go/issues/21527
|
||||
ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
75
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
generated
vendored
75
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
generated
vendored
@ -13,6 +13,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net/textproto"
|
||||
@ -177,8 +178,9 @@ func Decode(data []byte) (b *Block, rest []byte) {
|
||||
// message.
|
||||
type dashEscaper struct {
|
||||
buffered *bufio.Writer
|
||||
h hash.Hash
|
||||
hashers []hash.Hash // one per key in privateKeys
|
||||
hashType crypto.Hash
|
||||
toHash io.Writer // writes to all the hashes in hashers
|
||||
|
||||
atBeginningOfLine bool
|
||||
isFirstLine bool
|
||||
@ -186,8 +188,8 @@ type dashEscaper struct {
|
||||
whitespace []byte
|
||||
byteBuf []byte // a one byte buffer to save allocations
|
||||
|
||||
privateKey *packet.PrivateKey
|
||||
config *packet.Config
|
||||
privateKeys []*packet.PrivateKey
|
||||
config *packet.Config
|
||||
}
|
||||
|
||||
func (d *dashEscaper) Write(data []byte) (n int, err error) {
|
||||
@ -198,7 +200,7 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) {
|
||||
// The final CRLF isn't included in the hash so we have to wait
|
||||
// until this point (the start of the next line) before writing it.
|
||||
if !d.isFirstLine {
|
||||
d.h.Write(crlf)
|
||||
d.toHash.Write(crlf)
|
||||
}
|
||||
d.isFirstLine = false
|
||||
}
|
||||
@ -219,12 +221,12 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) {
|
||||
if _, err = d.buffered.Write(dashEscape); err != nil {
|
||||
return
|
||||
}
|
||||
d.h.Write(d.byteBuf)
|
||||
d.toHash.Write(d.byteBuf)
|
||||
d.atBeginningOfLine = false
|
||||
} else if b == '\n' {
|
||||
// Nothing to do because we delay writing CRLF to the hash.
|
||||
} else {
|
||||
d.h.Write(d.byteBuf)
|
||||
d.toHash.Write(d.byteBuf)
|
||||
d.atBeginningOfLine = false
|
||||
}
|
||||
if err = d.buffered.WriteByte(b); err != nil {
|
||||
@ -245,13 +247,13 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) {
|
||||
// Any buffered whitespace wasn't at the end of the line so
|
||||
// we need to write it out.
|
||||
if len(d.whitespace) > 0 {
|
||||
d.h.Write(d.whitespace)
|
||||
d.toHash.Write(d.whitespace)
|
||||
if _, err = d.buffered.Write(d.whitespace); err != nil {
|
||||
return
|
||||
}
|
||||
d.whitespace = d.whitespace[:0]
|
||||
}
|
||||
d.h.Write(d.byteBuf)
|
||||
d.toHash.Write(d.byteBuf)
|
||||
if err = d.buffered.WriteByte(b); err != nil {
|
||||
return
|
||||
}
|
||||
@ -269,25 +271,29 @@ func (d *dashEscaper) Close() (err error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
sig := new(packet.Signature)
|
||||
sig.SigType = packet.SigTypeText
|
||||
sig.PubKeyAlgo = d.privateKey.PubKeyAlgo
|
||||
sig.Hash = d.hashType
|
||||
sig.CreationTime = d.config.Now()
|
||||
sig.IssuerKeyId = &d.privateKey.KeyId
|
||||
|
||||
if err = sig.Sign(d.h, d.privateKey, d.config); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = sig.Serialize(out); err != nil {
|
||||
return
|
||||
t := d.config.Now()
|
||||
for i, k := range d.privateKeys {
|
||||
sig := new(packet.Signature)
|
||||
sig.SigType = packet.SigTypeText
|
||||
sig.PubKeyAlgo = k.PubKeyAlgo
|
||||
sig.Hash = d.hashType
|
||||
sig.CreationTime = t
|
||||
sig.IssuerKeyId = &k.KeyId
|
||||
|
||||
if err = sig.Sign(d.hashers[i], k, d.config); err != nil {
|
||||
return
|
||||
}
|
||||
if err = sig.Serialize(out); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = out.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
@ -300,8 +306,17 @@ func (d *dashEscaper) Close() (err error) {
|
||||
// Encode returns a WriteCloser which will clear-sign a message with privateKey
|
||||
// and write it to w. If config is nil, sensible defaults are used.
|
||||
func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
|
||||
if privateKey.Encrypted {
|
||||
return nil, errors.InvalidArgumentError("signing key is encrypted")
|
||||
return EncodeMulti(w, []*packet.PrivateKey{privateKey}, config)
|
||||
}
|
||||
|
||||
// EncodeMulti returns a WriteCloser which will clear-sign a message with all the
|
||||
// private keys indicated and write it to w. If config is nil, sensible defaults
|
||||
// are used.
|
||||
func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
|
||||
for _, k := range privateKeys {
|
||||
if k.Encrypted {
|
||||
return nil, errors.InvalidArgumentError(fmt.Sprintf("signing key %s is encrypted", k.KeyIdString()))
|
||||
}
|
||||
}
|
||||
|
||||
hashType := config.Hash()
|
||||
@ -313,7 +328,14 @@ func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (
|
||||
if !hashType.Available() {
|
||||
return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType)))
|
||||
}
|
||||
h := hashType.New()
|
||||
var hashers []hash.Hash
|
||||
var ws []io.Writer
|
||||
for range privateKeys {
|
||||
h := hashType.New()
|
||||
hashers = append(hashers, h)
|
||||
ws = append(ws, h)
|
||||
}
|
||||
toHash := io.MultiWriter(ws...)
|
||||
|
||||
buffered := bufio.NewWriter(w)
|
||||
// start has a \n at the beginning that we don't want here.
|
||||
@ -338,16 +360,17 @@ func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (
|
||||
|
||||
plaintext = &dashEscaper{
|
||||
buffered: buffered,
|
||||
h: h,
|
||||
hashers: hashers,
|
||||
hashType: hashType,
|
||||
toHash: toHash,
|
||||
|
||||
atBeginningOfLine: true,
|
||||
isFirstLine: true,
|
||||
|
||||
byteBuf: make([]byte, 1),
|
||||
|
||||
privateKey: privateKey,
|
||||
config: config,
|
||||
privateKeys: privateKeys,
|
||||
config: config,
|
||||
}
|
||||
|
||||
return
|
||||
|
70
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
generated
vendored
70
vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
generated
vendored
@ -6,8 +6,11 @@ package clearsign
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
func testParse(t *testing.T, input []byte, expected, expectedPlaintext string) {
|
||||
@ -125,6 +128,71 @@ func TestSigning(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// We use this to make test keys, so that they aren't all the same.
|
||||
type quickRand byte
|
||||
|
||||
func (qr *quickRand) Read(p []byte) (int, error) {
|
||||
for i := range p {
|
||||
p[i] = byte(*qr)
|
||||
}
|
||||
*qr++
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func TestMultiSign(t *testing.T) {
|
||||
zero := quickRand(0)
|
||||
config := packet.Config{Rand: &zero}
|
||||
|
||||
for nKeys := 0; nKeys < 4; nKeys++ {
|
||||
nextTest:
|
||||
for nExtra := 0; nExtra < 4; nExtra++ {
|
||||
var signKeys []*packet.PrivateKey
|
||||
var verifyKeys openpgp.EntityList
|
||||
|
||||
desc := fmt.Sprintf("%d keys; %d of which will be used to verify", nKeys+nExtra, nKeys)
|
||||
for i := 0; i < nKeys+nExtra; i++ {
|
||||
e, err := openpgp.NewEntity("name", "comment", "email", &config)
|
||||
if err != nil {
|
||||
t.Errorf("cannot create key: %v", err)
|
||||
continue nextTest
|
||||
}
|
||||
if i < nKeys {
|
||||
verifyKeys = append(verifyKeys, e)
|
||||
}
|
||||
signKeys = append(signKeys, e.PrivateKey)
|
||||
}
|
||||
|
||||
input := []byte("this is random text\r\n4 17")
|
||||
var output bytes.Buffer
|
||||
w, err := EncodeMulti(&output, signKeys, nil)
|
||||
if err != nil {
|
||||
t.Errorf("EncodeMulti (%s) failed: %v", desc, err)
|
||||
}
|
||||
if _, err := w.Write(input); err != nil {
|
||||
t.Errorf("Write(%q) to signer (%s) failed: %v", string(input), desc, err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
t.Errorf("Close() of signer (%s) failed: %v", desc, err)
|
||||
}
|
||||
|
||||
block, _ := Decode(output.Bytes())
|
||||
if string(block.Bytes) != string(input) {
|
||||
t.Errorf("Inline data didn't match original; got %q want %q", string(block.Bytes), string(input))
|
||||
}
|
||||
_, err = openpgp.CheckDetachedSignature(verifyKeys, bytes.NewReader(block.Bytes), block.ArmoredSignature.Body)
|
||||
if nKeys == 0 {
|
||||
if err == nil {
|
||||
t.Errorf("verifying inline (%s) succeeded; want failure", desc)
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("verifying inline (%s) failed (%v); want success", desc, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var clearsignInput = []byte(`
|
||||
;lasjlkfdsa
|
||||
|
||||
|
165
vendor/golang.org/x/crypto/openpgp/keys.go
generated
vendored
165
vendor/golang.org/x/crypto/openpgp/keys.go
generated
vendored
@ -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,32 +345,8 @@ EachPacket:
|
||||
|
||||
switch pkt := p.(type) {
|
||||
case *packet.UserId:
|
||||
current = new(Identity)
|
||||
current.Name = pkt.Id
|
||||
current.UserId = pkt
|
||||
e.Identities[pkt.Id] = current
|
||||
|
||||
for {
|
||||
p, err = packets.Next()
|
||||
if err == io.EOF {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, ok := p.(*packet.Signature)
|
||||
if !ok {
|
||||
return nil, errors.StructuralError("user ID packet not followed by self-signature")
|
||||
}
|
||||
|
||||
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
|
||||
break
|
||||
}
|
||||
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 {
|
||||
@ -380,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)
|
||||
@ -425,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
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return errors.StructuralError("subkey signature invalid: " + err.Error())
|
||||
}
|
||||
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
|
||||
@ -486,7 +531,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
||||
}
|
||||
isPrimaryId := true
|
||||
e.Identities[uid.Id] = &Identity{
|
||||
Name: uid.Name,
|
||||
Name: uid.Id,
|
||||
UserId: uid,
|
||||
SelfSignature: &packet.Signature{
|
||||
CreationTime: currentTime,
|
||||
@ -500,6 +545,10 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
||||
IssuerKeyId: &e.PrimaryKey.KeyId,
|
||||
},
|
||||
}
|
||||
err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the user passes in a DefaultHash via packet.Config,
|
||||
// set the PreferredHash for the SelfSignature.
|
||||
@ -507,6 +556,11 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
||||
e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)}
|
||||
}
|
||||
|
||||
// Likewise for DefaultCipher.
|
||||
if config != nil && config.DefaultCipher != 0 {
|
||||
e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)}
|
||||
}
|
||||
|
||||
e.Subkeys = make([]Subkey, 1)
|
||||
e.Subkeys[0] = Subkey{
|
||||
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
|
||||
@ -524,13 +578,16 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
|
||||
}
|
||||
e.Subkeys[0].PublicKey.IsSubkey = true
|
||||
e.Subkeys[0].PrivateKey.IsSubkey = true
|
||||
|
||||
err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// SerializePrivate serializes an Entity, including private key material, to
|
||||
// the given Writer. For now, it must only be used on an Entity returned from
|
||||
// NewEntity.
|
||||
// SerializePrivate serializes an Entity, including private key material, but
|
||||
// excluding signatures from other entities, to the given Writer.
|
||||
// Identities and subkeys are re-signed in case they changed since NewEntry.
|
||||
// If config is nil, sensible defaults will be used.
|
||||
func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
|
||||
err = e.PrivateKey.Serialize(w)
|
||||
@ -568,8 +625,8 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error
|
||||
return nil
|
||||
}
|
||||
|
||||
// Serialize writes the public part of the given Entity to w. (No private
|
||||
// key material will be output).
|
||||
// Serialize writes the public part of the given Entity to w, including
|
||||
// signatures from other entities. No private key material will be output.
|
||||
func (e *Entity) Serialize(w io.Writer) error {
|
||||
err := e.PrimaryKey.Serialize(w)
|
||||
if err != nil {
|
||||
|
268
vendor/golang.org/x/crypto/openpgp/keys_test.go
generated
vendored
268
vendor/golang.org/x/crypto/openpgp/keys_test.go
generated
vendored
File diff suppressed because one or more lines are too long
9
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go
generated
vendored
9
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go
generated
vendored
@ -42,12 +42,18 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) {
|
||||
switch e.Algo {
|
||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||
e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case PubKeyAlgoElGamal:
|
||||
e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
_, err = consumeAll(r)
|
||||
return
|
||||
@ -72,7 +78,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
|
||||
// padding oracle attacks.
|
||||
switch priv.PubKeyAlgo {
|
||||
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
|
||||
b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes)
|
||||
k := priv.PrivateKey.(*rsa.PrivateKey)
|
||||
b, err = rsa.DecryptPKCS1v15(config.Random(), k, padToKeySize(&k.PublicKey, e.encryptedMPI1.bytes))
|
||||
case PubKeyAlgoElGamal:
|
||||
c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
|
||||
c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
|
||||
|
63
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go
generated
vendored
63
vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go
generated
vendored
@ -39,39 +39,44 @@ var encryptedKeyPriv = &PrivateKey{
|
||||
}
|
||||
|
||||
func TestDecryptingEncryptedKey(t *testing.T) {
|
||||
const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
|
||||
const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
|
||||
for i, encryptedKeyHex := range []string{
|
||||
"c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8",
|
||||
// MPI can be shorter than the length of the key.
|
||||
"c18b032a67d68660df41c70103f8e520c52ae9807183c669ce26e772e482dc5d8cf60e6f59316e145be14d2e5221ee69550db1d5618a8cb002a719f1f0b9345bde21536d410ec90ba86cac37748dec7933eb7f9873873b2d61d3321d1cd44535014f6df58f7bc0c7afb5edc38e1a974428997d2f747f9a173bea9ca53079b409517d332df62d805564cffc9be6",
|
||||
} {
|
||||
const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
|
||||
|
||||
p, err := Read(readerFromHex(encryptedKeyHex))
|
||||
if err != nil {
|
||||
t.Errorf("error from Read: %s", err)
|
||||
return
|
||||
}
|
||||
ek, ok := p.(*EncryptedKey)
|
||||
if !ok {
|
||||
t.Errorf("didn't parse an EncryptedKey, got %#v", p)
|
||||
return
|
||||
}
|
||||
p, err := Read(readerFromHex(encryptedKeyHex))
|
||||
if err != nil {
|
||||
t.Errorf("#%d: error from Read: %s", i, err)
|
||||
return
|
||||
}
|
||||
ek, ok := p.(*EncryptedKey)
|
||||
if !ok {
|
||||
t.Errorf("#%d: didn't parse an EncryptedKey, got %#v", i, p)
|
||||
return
|
||||
}
|
||||
|
||||
if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
|
||||
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
|
||||
return
|
||||
}
|
||||
if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
|
||||
t.Errorf("#%d: unexpected EncryptedKey contents: %#v", i, ek)
|
||||
return
|
||||
}
|
||||
|
||||
err = ek.Decrypt(encryptedKeyPriv, nil)
|
||||
if err != nil {
|
||||
t.Errorf("error from Decrypt: %s", err)
|
||||
return
|
||||
}
|
||||
err = ek.Decrypt(encryptedKeyPriv, nil)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: error from Decrypt: %s", i, err)
|
||||
return
|
||||
}
|
||||
|
||||
if ek.CipherFunc != CipherAES256 {
|
||||
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
|
||||
return
|
||||
}
|
||||
if ek.CipherFunc != CipherAES256 {
|
||||
t.Errorf("#%d: unexpected EncryptedKey contents: %#v", i, ek)
|
||||
return
|
||||
}
|
||||
|
||||
keyHex := fmt.Sprintf("%x", ek.Key)
|
||||
if keyHex != expectedKeyHex {
|
||||
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
|
||||
keyHex := fmt.Sprintf("%x", ek.Key)
|
||||
if keyHex != expectedKeyHex {
|
||||
t.Errorf("#%d: bad key, got %s want %s", i, keyHex, expectedKeyHex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +126,7 @@ func TestEncryptingEncryptedKey(t *testing.T) {
|
||||
|
||||
keyHex := fmt.Sprintf("%x", ek.Key)
|
||||
if keyHex != expectedKeyHex {
|
||||
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
|
||||
t.Errorf("bad key, got %s want %s", keyHex, expectedKeyHex)
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user