vendor: updating dependencies
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
parent
c5b7548e35
commit
50d22c5135
428 changed files with 153917 additions and 2562 deletions
12
glide.lock
generated
12
glide.lock
generated
|
@ -1,8 +1,14 @@
|
||||||
hash: 90db837f2d27de645d9f48fa1be54b4f9d83f0cb9343ce98fa61e1b55b2828b5
|
hash: c4cfd3ace8e3926093aacecfa0f22fbeb5b2a7cb53e0b12a48b5108f6c83d9b8
|
||||||
updated: 2017-01-19T17:18:33.464668206-05:00
|
updated: 2017-06-24T14:24:17.116476656-04:00
|
||||||
imports:
|
imports:
|
||||||
|
- name: github.com/Sirupsen/logrus
|
||||||
|
version: 202f25545ea4cf9b191ff7f846df5d87c9382c2b
|
||||||
- name: golang.org/x/crypto
|
- name: golang.org/x/crypto
|
||||||
version: b8a2a83acfe6e6770b75de42d5ff4c67596675c0
|
version: adbae1b6b6fb4b02448a0fc0dbbc9ba2b95b294d
|
||||||
subpackages:
|
subpackages:
|
||||||
- ripemd160
|
- ripemd160
|
||||||
|
- name: golang.org/x/sys
|
||||||
|
version: c23410a886927bab8ca5e80b08af6a56faeb330d
|
||||||
|
subpackages:
|
||||||
|
- unix
|
||||||
testImports: []
|
testImports: []
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package: github.com/vbatts/go-mtree
|
package: github.com/vbatts/go-mtree
|
||||||
|
description: File systems verification utility and library, in likeness of mtree(8)
|
||||||
homepage: https://github.com/vbatts/go-mtree
|
homepage: https://github.com/vbatts/go-mtree
|
||||||
license: BSD-3-Clause
|
license: BSD-3-Clause
|
||||||
description: File systems verification utility and library, in likeness of mtree(8)
|
|
||||||
import:
|
import:
|
||||||
- package: golang.org/x/crypto
|
- package: golang.org/x/crypto
|
||||||
subpackages:
|
subpackages:
|
||||||
- ripemd160
|
- ripemd160
|
||||||
|
- package: github.com/Sirupsen/logrus
|
||||||
|
version: ^1.0.0
|
||||||
|
|
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
1
vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
logrus
|
13
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
13
vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.6.x
|
||||||
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- tip
|
||||||
|
env:
|
||||||
|
- GOMAXPROCS=4 GORACE=halt_on_error=1
|
||||||
|
install:
|
||||||
|
- go get github.com/stretchr/testify/assert
|
||||||
|
script:
|
||||||
|
- go test -race -v .
|
||||||
|
- cd hooks/null && go test -race -v .
|
100
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
100
vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
# 1.0.0
|
||||||
|
|
||||||
|
* Officially changed name to lower-case
|
||||||
|
* bug: colors on Windows 10 (#541)
|
||||||
|
* bug: fix race in accessing level (#512)
|
||||||
|
|
||||||
|
# 0.11.5
|
||||||
|
|
||||||
|
* feature: add writer and writerlevel to entry (#372)
|
||||||
|
|
||||||
|
# 0.11.4
|
||||||
|
|
||||||
|
* bug: fix undefined variable on solaris (#493)
|
||||||
|
|
||||||
|
# 0.11.3
|
||||||
|
|
||||||
|
* formatter: configure quoting of empty values (#484)
|
||||||
|
* formatter: configure quoting character (default is `"`) (#484)
|
||||||
|
* bug: fix not importing io correctly in non-linux environments (#481)
|
||||||
|
|
||||||
|
# 0.11.2
|
||||||
|
|
||||||
|
* bug: fix windows terminal detection (#476)
|
||||||
|
|
||||||
|
# 0.11.1
|
||||||
|
|
||||||
|
* bug: fix tty detection with custom out (#471)
|
||||||
|
|
||||||
|
# 0.11.0
|
||||||
|
|
||||||
|
* performance: Use bufferpool to allocate (#370)
|
||||||
|
* terminal: terminal detection for app-engine (#343)
|
||||||
|
* feature: exit handler (#375)
|
||||||
|
|
||||||
|
# 0.10.0
|
||||||
|
|
||||||
|
* feature: Add a test hook (#180)
|
||||||
|
* feature: `ParseLevel` is now case-insensitive (#326)
|
||||||
|
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
|
||||||
|
* performance: avoid re-allocations on `WithFields` (#335)
|
||||||
|
|
||||||
|
# 0.9.0
|
||||||
|
|
||||||
|
* logrus/text_formatter: don't emit empty msg
|
||||||
|
* logrus/hooks/airbrake: move out of main repository
|
||||||
|
* logrus/hooks/sentry: move out of main repository
|
||||||
|
* logrus/hooks/papertrail: move out of main repository
|
||||||
|
* logrus/hooks/bugsnag: move out of main repository
|
||||||
|
* logrus/core: run tests with `-race`
|
||||||
|
* logrus/core: detect TTY based on `stderr`
|
||||||
|
* logrus/core: support `WithError` on logger
|
||||||
|
* logrus/core: Solaris support
|
||||||
|
|
||||||
|
# 0.8.7
|
||||||
|
|
||||||
|
* logrus/core: fix possible race (#216)
|
||||||
|
* logrus/doc: small typo fixes and doc improvements
|
||||||
|
|
||||||
|
|
||||||
|
# 0.8.6
|
||||||
|
|
||||||
|
* hooks/raven: allow passing an initialized client
|
||||||
|
|
||||||
|
# 0.8.5
|
||||||
|
|
||||||
|
* logrus/core: revert #208
|
||||||
|
|
||||||
|
# 0.8.4
|
||||||
|
|
||||||
|
* formatter/text: fix data race (#218)
|
||||||
|
|
||||||
|
# 0.8.3
|
||||||
|
|
||||||
|
* logrus/core: fix entry log level (#208)
|
||||||
|
* logrus/core: improve performance of text formatter by 40%
|
||||||
|
* logrus/core: expose `LevelHooks` type
|
||||||
|
* logrus/core: add support for DragonflyBSD and NetBSD
|
||||||
|
* formatter/text: print structs more verbosely
|
||||||
|
|
||||||
|
# 0.8.2
|
||||||
|
|
||||||
|
* logrus: fix more Fatal family functions
|
||||||
|
|
||||||
|
# 0.8.1
|
||||||
|
|
||||||
|
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
||||||
|
|
||||||
|
# 0.8.0
|
||||||
|
|
||||||
|
* logrus: defaults to stderr instead of stdout
|
||||||
|
* hooks/sentry: add special field for `*http.Request`
|
||||||
|
* formatter/text: ignore Windows for colors
|
||||||
|
|
||||||
|
# 0.7.3
|
||||||
|
|
||||||
|
* formatter/\*: allow configuration of timestamp layout
|
||||||
|
|
||||||
|
# 0.7.2
|
||||||
|
|
||||||
|
* formatter/text: Add configuration option for time format (#158)
|
21
vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
21
vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Simon Eskildsen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
501
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
501
vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
|
@ -0,0 +1,501 @@
|
||||||
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
|
||||||
|
|
||||||
|
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||||
|
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||||
|
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
|
||||||
|
many large deployments. The core API is unlikely to change much but please
|
||||||
|
version control your Logrus to make sure you aren't fetching latest `master` on
|
||||||
|
every build.**
|
||||||
|
|
||||||
|
**Seeing weird case-sensitive problems?** Unfortunately, the author failed to
|
||||||
|
realize the consequences of renaming to lower-case. Due to the Go package
|
||||||
|
environment, this caused issues. Regretfully, there's no turning back now.
|
||||||
|
Everything using `logrus` will need to use the lower-case:
|
||||||
|
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
|
||||||
|
|
||||||
|
I am terribly sorry for this inconvenience. Logrus strives hard for backwards
|
||||||
|
compatibility, and the author failed to realize the cascading consequences of
|
||||||
|
such a name-change. To fix Glide, see [these
|
||||||
|
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
|
||||||
|
|
||||||
|
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||||
|
plain text):
|
||||||
|
|
||||||
|
![Colored](http://i.imgur.com/PY7qMwd.png)
|
||||||
|
|
||||||
|
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
|
||||||
|
or Splunk:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||||
|
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||||
|
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||||
|
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||||
|
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||||
|
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
|
||||||
|
attached, the output is compatible with the
|
||||||
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Case-sensitivity
|
||||||
|
|
||||||
|
The organization's name was changed to lower-case--and this will not be changed
|
||||||
|
back. If you are getting import conflicts due to case sensitivity, please use
|
||||||
|
the lower-case import: `github.com/sirupsen/logrus`.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||||
|
replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
|
||||||
|
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||||
|
want:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Log as JSON instead of the default ASCII formatter.
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
|
||||||
|
// Output to stdout instead of the default stderr
|
||||||
|
// Can be any io.Writer, see below for File example
|
||||||
|
log.SetOutput(os.Stdout)
|
||||||
|
|
||||||
|
// Only log the warning severity or above.
|
||||||
|
log.SetLevel(log.WarnLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
|
||||||
|
// A common pattern is to re-use fields between logging statements by re-using
|
||||||
|
// the logrus.Entry returned from WithFields()
|
||||||
|
contextLogger := log.WithFields(log.Fields{
|
||||||
|
"common": "this is a common field",
|
||||||
|
"other": "I also should be logged always",
|
||||||
|
})
|
||||||
|
|
||||||
|
contextLogger.Info("I'll be logged with common and other field")
|
||||||
|
contextLogger.Info("Me too")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more advanced usage such as logging to multiple locations from the same
|
||||||
|
application, you can also create an instance of the `logrus` Logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a new instance of the logger. You can have any number of instances.
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// The API for setting attributes is a little different than the package level
|
||||||
|
// exported logger. See Godoc.
|
||||||
|
log.Out = os.Stdout
|
||||||
|
|
||||||
|
// You could set this to any `io.Writer` such as a file
|
||||||
|
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
|
||||||
|
// if err == nil {
|
||||||
|
// log.Out = file
|
||||||
|
// } else {
|
||||||
|
// log.Info("Failed to log to file, using default stderr")
|
||||||
|
// }
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
Logrus encourages careful, structured logging through logging fields instead of
|
||||||
|
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||||
|
to send event %s to topic %s with key %d")`, you should log the much more
|
||||||
|
discoverable:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"event": event,
|
||||||
|
"topic": topic,
|
||||||
|
"key": key,
|
||||||
|
}).Fatal("Failed to send event")
|
||||||
|
```
|
||||||
|
|
||||||
|
We've found this API forces you to think about logging in a way that produces
|
||||||
|
much more useful logging messages. We've been in countless situations where just
|
||||||
|
a single added field to a log statement that was already there would've saved us
|
||||||
|
hours. The `WithFields` call is optional.
|
||||||
|
|
||||||
|
In general, with Logrus using any of the `printf`-family functions should be
|
||||||
|
seen as a hint you should add a field, however, you can still use the
|
||||||
|
`printf`-family functions with Logrus.
|
||||||
|
|
||||||
|
#### Default Fields
|
||||||
|
|
||||||
|
Often it's helpful to have fields _always_ attached to log statements in an
|
||||||
|
application or parts of one. For example, you may want to always log the
|
||||||
|
`request_id` and `user_ip` in the context of a request. Instead of writing
|
||||||
|
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
|
||||||
|
every line, you can create a `logrus.Entry` to pass around instead:
|
||||||
|
|
||||||
|
```go
|
||||||
|
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
|
||||||
|
requestLogger.Info("something happened on that request") # will log request_id and user_ip
|
||||||
|
requestLogger.Warn("something not great happened")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Hooks
|
||||||
|
|
||||||
|
You can add hooks for logging levels. For example to send errors to an exception
|
||||||
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||||
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
|
`init`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
|
||||||
|
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||||
|
"log/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
|
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
|
||||||
|
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to connect to local syslog daemon")
|
||||||
|
} else {
|
||||||
|
log.AddHook(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
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) |
|
||||||
|
| [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/goibibo/KafkaLogrus) | Hook for logging to kafka |
|
||||||
|
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||||
|
| [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 |
|
||||||
|
| [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) |
|
||||||
|
| [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. |
|
||||||
|
| [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/) |
|
||||||
|
|
||||||
|
#### Level logging
|
||||||
|
|
||||||
|
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.Debug("Useful debugging information.")
|
||||||
|
log.Info("Something noteworthy happened!")
|
||||||
|
log.Warn("You should probably take a look at this.")
|
||||||
|
log.Error("Something failed but I'm not quitting.")
|
||||||
|
// Calls os.Exit(1) after logging
|
||||||
|
log.Fatal("Bye.")
|
||||||
|
// Calls panic() after logging
|
||||||
|
log.Panic("I'm bailing.")
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set the logging level on a `Logger`, then it will only log entries with
|
||||||
|
that severity or anything above it:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
||||||
|
log.SetLevel(log.InfoLevel)
|
||||||
|
```
|
||||||
|
|
||||||
|
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
||||||
|
environment if your application has that.
|
||||||
|
|
||||||
|
#### Entries
|
||||||
|
|
||||||
|
Besides the fields added with `WithField` or `WithFields` some fields are
|
||||||
|
automatically added to all logging events:
|
||||||
|
|
||||||
|
1. `time`. The timestamp when the entry was created.
|
||||||
|
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
||||||
|
the `AddFields` call. E.g. `Failed to send event.`
|
||||||
|
3. `level`. The logging level. E.g. `info`.
|
||||||
|
|
||||||
|
#### Environments
|
||||||
|
|
||||||
|
Logrus has no notion of environment.
|
||||||
|
|
||||||
|
If you wish for hooks and formatters to only be used in specific environments,
|
||||||
|
you should handle that yourself. For example, if your application has a global
|
||||||
|
variable `Environment`, which is a string representation of the environment you
|
||||||
|
could do:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// do something here to set environment depending on an environment variable
|
||||||
|
// or command-line flag
|
||||||
|
if Environment == "production" {
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
} else {
|
||||||
|
// The TextFormatter is default, you don't actually have to do this.
|
||||||
|
log.SetFormatter(&log.TextFormatter{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This configuration is how `logrus` was intended to be used, but JSON in
|
||||||
|
production is mostly only useful if you do log aggregation with tools like
|
||||||
|
Splunk or Logstash.
|
||||||
|
|
||||||
|
#### Formatters
|
||||||
|
|
||||||
|
The built-in logging formatters are:
|
||||||
|
|
||||||
|
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||||
|
without colors.
|
||||||
|
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||||
|
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).
|
||||||
|
* 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).
|
||||||
|
|
||||||
|
Third party logging formatters:
|
||||||
|
|
||||||
|
* [`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̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
|
||||||
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||||
|
default ones (see Entries section above):
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MyJSONFormatter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetFormatter(new(MyJSONFormatter))
|
||||||
|
|
||||||
|
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
// Note this doesn't include Time, Level and Message which are available on
|
||||||
|
// the Entry. Consult `godoc` on information about those fields or read the
|
||||||
|
// source of the official loggers.
|
||||||
|
serialized, err := json.Marshal(entry.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Logger as an `io.Writer`
|
||||||
|
|
||||||
|
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
||||||
|
|
||||||
|
```go
|
||||||
|
w := logger.Writer()
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
srv := http.Server{
|
||||||
|
// create a stdlib log.Logger that writes to
|
||||||
|
// logrus.Logger.
|
||||||
|
ErrorLog: log.New(w, "", 0),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each line written to that writer will be printed the usual way, using formatters
|
||||||
|
and hooks. The level for those entries is `info`.
|
||||||
|
|
||||||
|
This means that we can override the standard library logger easily:
|
||||||
|
|
||||||
|
```go
|
||||||
|
logger := logrus.New()
|
||||||
|
logger.Formatter = &logrus.JSONFormatter{}
|
||||||
|
|
||||||
|
// Use logrus for standard log output
|
||||||
|
// Note that `log` here references stdlib's log
|
||||||
|
// Not logrus imported under the name `log`.
|
||||||
|
log.SetOutput(logger.Writer())
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Rotation
|
||||||
|
|
||||||
|
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||||
|
external program (like `logrotate(8)`) that can compress and delete old log
|
||||||
|
entries. It should not be a feature of the application-level logger.
|
||||||
|
|
||||||
|
#### Tools
|
||||||
|
|
||||||
|
| Tool | Description |
|
||||||
|
| ---- | ----------- |
|
||||||
|
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.|
|
||||||
|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
|
||||||
|
|
||||||
|
#### Testing
|
||||||
|
|
||||||
|
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
|
||||||
|
|
||||||
|
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook
|
||||||
|
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
|
||||||
|
|
||||||
|
```go
|
||||||
|
import(
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/sirupsen/logrus/hooks/null"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSomething(t*testing.T){
|
||||||
|
logger, hook := null.NewNullLogger()
|
||||||
|
logger.Error("Helloerror")
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(hook.Entries))
|
||||||
|
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
|
||||||
|
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
|
||||||
|
|
||||||
|
hook.Reset()
|
||||||
|
assert.Nil(t, hook.LastEntry())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fatal handlers
|
||||||
|
|
||||||
|
Logrus can register one or more functions that will be called when any `fatal`
|
||||||
|
level message is logged. The registered handlers will be executed before
|
||||||
|
logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need
|
||||||
|
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
|
||||||
|
|
||||||
|
```
|
||||||
|
...
|
||||||
|
handler := func() {
|
||||||
|
// gracefully shutdown something...
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
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:
|
||||||
|
|
||||||
|
* You have no hooks registered, or hooks calling is already thread-safe.
|
||||||
|
|
||||||
|
* Writing to logger.Out is already thread-safe, for example:
|
||||||
|
|
||||||
|
1) logger.Out is protected by locks.
|
||||||
|
|
||||||
|
2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing)
|
||||||
|
|
||||||
|
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
|
64
vendor/github.com/Sirupsen/logrus/alt_exit.go
generated
vendored
Normal file
64
vendor/github.com/Sirupsen/logrus/alt_exit.go
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// The following code was sourced and modified from the
|
||||||
|
// https://github.com/tebeka/atexit package governed by the following license:
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
// the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
// subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var handlers = []func(){}
|
||||||
|
|
||||||
|
func runHandler(handler func()) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runHandlers() {
|
||||||
|
for _, handler := range handlers {
|
||||||
|
runHandler(handler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
|
||||||
|
func Exit(code int) {
|
||||||
|
runHandlers()
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
|
||||||
|
// all handlers. The handlers will also be invoked when any Fatal log entry is
|
||||||
|
// made.
|
||||||
|
//
|
||||||
|
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||||
|
// message but also needs to gracefully shutdown. An example usecase could be
|
||||||
|
// closing database connections, or sending a alert that the application is
|
||||||
|
// closing.
|
||||||
|
func RegisterExitHandler(handler func()) {
|
||||||
|
handlers = append(handlers, handler)
|
||||||
|
}
|
74
vendor/github.com/Sirupsen/logrus/alt_exit_test.go
generated
vendored
Normal file
74
vendor/github.com/Sirupsen/logrus/alt_exit_test.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os/exec"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegister(t *testing.T) {
|
||||||
|
current := len(handlers)
|
||||||
|
RegisterExitHandler(func() {})
|
||||||
|
if len(handlers) != current+1 {
|
||||||
|
t.Fatalf("can't add handler")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler(t *testing.T) {
|
||||||
|
gofile := "/tmp/testprog.go"
|
||||||
|
if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil {
|
||||||
|
t.Fatalf("can't create go file")
|
||||||
|
}
|
||||||
|
|
||||||
|
outfile := "/tmp/testprog.out"
|
||||||
|
arg := time.Now().UTC().String()
|
||||||
|
err := exec.Command("go", "run", gofile, outfile, arg).Run()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("completed normally, should have failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(outfile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("can't read output file %s", outfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(data) != arg {
|
||||||
|
t.Fatalf("bad data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var testprog = []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"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var outfile = ""
|
||||||
|
var data = ""
|
||||||
|
|
||||||
|
func handler() {
|
||||||
|
ioutil.WriteFile(outfile, []byte(data), 0666)
|
||||||
|
}
|
||||||
|
|
||||||
|
func badHandler() {
|
||||||
|
n := 0
|
||||||
|
fmt.Println(1/n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
outfile = flag.Arg(0)
|
||||||
|
data = flag.Arg(1)
|
||||||
|
|
||||||
|
logrus.RegisterExitHandler(handler)
|
||||||
|
logrus.RegisterExitHandler(badHandler)
|
||||||
|
logrus.Fatal("Bye bye")
|
||||||
|
}
|
||||||
|
`)
|
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
26
vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||||
|
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"number": 1,
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
|
||||||
|
Output:
|
||||||
|
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||||
|
|
||||||
|
For a full guide visit https://github.com/sirupsen/logrus
|
||||||
|
*/
|
||||||
|
package logrus
|
275
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
275
vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bufferPool *sync.Pool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
bufferPool = &sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return new(bytes.Buffer)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
type Entry struct {
|
||||||
|
Logger *Logger
|
||||||
|
|
||||||
|
// Contains all the fields set by the user.
|
||||||
|
Data Fields
|
||||||
|
|
||||||
|
// 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 Level
|
||||||
|
|
||||||
|
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Message string
|
||||||
|
|
||||||
|
// When formatter is called in entry.log(), an Buffer may be set to entry
|
||||||
|
Buffer *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntry(logger *Logger) *Entry {
|
||||||
|
return &Entry{
|
||||||
|
Logger: logger,
|
||||||
|
// Default is three fields, give a little extra room
|
||||||
|
Data: make(Fields, 5),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the string representation from the reader and ultimately the
|
||||||
|
// formatter.
|
||||||
|
func (entry *Entry) String() (string, error) {
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
str := string(serialized)
|
||||||
|
return str, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||||
|
func (entry *Entry) WithError(err error) *Entry {
|
||||||
|
return entry.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a single field to the Entry.
|
||||||
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
|
return entry.WithFields(Fields{key: value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a map of fields to the Entry.
|
||||||
|
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
|
data := make(Fields, len(entry.Data)+len(fields))
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range fields {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
return &Entry{Logger: entry.Logger, Data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
entry.Level = level
|
||||||
|
entry.Message = msg
|
||||||
|
|
||||||
|
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
buffer = bufferPool.Get().(*bytes.Buffer)
|
||||||
|
buffer.Reset()
|
||||||
|
defer bufferPool.Put(buffer)
|
||||||
|
entry.Buffer = buffer
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(&entry)
|
||||||
|
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
|
||||||
|
// directly here.
|
||||||
|
if level <= PanicLevel {
|
||||||
|
panic(&entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= DebugLevel {
|
||||||
|
entry.log(DebugLevel, fmt.Sprint(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...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warn(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= WarnLevel {
|
||||||
|
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warning(args ...interface{}) {
|
||||||
|
entry.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Error(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= ErrorLevel {
|
||||||
|
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatal(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= FatalLevel {
|
||||||
|
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panic(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= PanicLevel {
|
||||||
|
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
panic(fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Printf family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= DebugLevel {
|
||||||
|
entry.Debug(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= InfoLevel {
|
||||||
|
entry.Info(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||||
|
entry.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= WarnLevel {
|
||||||
|
entry.Warn(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= ErrorLevel {
|
||||||
|
entry.Error(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= FatalLevel {
|
||||||
|
entry.Fatal(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= PanicLevel {
|
||||||
|
entry.Panic(fmt.Sprintf(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) Infoln(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= InfoLevel {
|
||||||
|
entry.Info(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Println(args ...interface{}) {
|
||||||
|
entry.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnln(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= WarnLevel {
|
||||||
|
entry.Warn(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningln(args ...interface{}) {
|
||||||
|
entry.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorln(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= ErrorLevel {
|
||||||
|
entry.Error(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= FatalLevel {
|
||||||
|
entry.Fatal(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
|
if entry.Logger.level() >= PanicLevel {
|
||||||
|
entry.Panic(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||||
|
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||||
|
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||||
|
// string allocation, we do the simplest thing.
|
||||||
|
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||||
|
msg := fmt.Sprintln(args...)
|
||||||
|
return msg[:len(msg)-1]
|
||||||
|
}
|
77
vendor/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
Normal file
77
vendor/github.com/Sirupsen/logrus/entry_test.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEntryWithError(t *testing.T) {
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
ErrorKey = "error"
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := fmt.Errorf("kaboom at layer %d", 4711)
|
||||||
|
|
||||||
|
assert.Equal(err, WithError(err).Data["error"])
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &bytes.Buffer{}
|
||||||
|
entry := NewEntry(logger)
|
||||||
|
|
||||||
|
assert.Equal(err, entry.WithError(err).Data["error"])
|
||||||
|
|
||||||
|
ErrorKey = "err"
|
||||||
|
|
||||||
|
assert.Equal(err, entry.WithError(err).Data["err"])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEntryPanicln(t *testing.T) {
|
||||||
|
errBoom := fmt.Errorf("boom time")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
p := recover()
|
||||||
|
assert.NotNil(t, p)
|
||||||
|
|
||||||
|
switch pVal := p.(type) {
|
||||||
|
case *Entry:
|
||||||
|
assert.Equal(t, "kaboom", pVal.Message)
|
||||||
|
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||||
|
default:
|
||||||
|
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &bytes.Buffer{}
|
||||||
|
entry := NewEntry(logger)
|
||||||
|
entry.WithField("err", errBoom).Panicln("kaboom")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEntryPanicf(t *testing.T) {
|
||||||
|
errBoom := fmt.Errorf("boom again")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
p := recover()
|
||||||
|
assert.NotNil(t, p)
|
||||||
|
|
||||||
|
switch pVal := p.(type) {
|
||||||
|
case *Entry:
|
||||||
|
assert.Equal(t, "kaboom true", pVal.Message)
|
||||||
|
assert.Equal(t, errBoom, pVal.Data["err"])
|
||||||
|
default:
|
||||||
|
t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &bytes.Buffer{}
|
||||||
|
entry := NewEntry(logger)
|
||||||
|
entry.WithField("err", errBoom).Panicf("kaboom %v", true)
|
||||||
|
}
|
59
vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
Normal file
59
vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
// "os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.Formatter = new(logrus.JSONFormatter)
|
||||||
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
|
|
||||||
|
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
|
||||||
|
// if err == nil {
|
||||||
|
// log.Out = file
|
||||||
|
// } else {
|
||||||
|
// log.Info("Failed to log to file, using default stderr")
|
||||||
|
// }
|
||||||
|
|
||||||
|
log.Level = logrus.DebugLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"err": err,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"number": 8,
|
||||||
|
}).Debug("Started observing beach")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"temperature": -4,
|
||||||
|
}).Debug("Temperature changes")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "orca",
|
||||||
|
"size": 9009,
|
||||||
|
}).Panic("It's over 9000!")
|
||||||
|
}
|
30
vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
Normal file
30
vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
|
log.Hooks.Add(airbrake.NewHook(123, "xyz", "development"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
}
|
193
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
193
vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// std is the name of the standard logger in stdlib `log`
|
||||||
|
std = New()
|
||||||
|
)
|
||||||
|
|
||||||
|
func StandardLogger() *Logger {
|
||||||
|
return std
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOutput sets the standard logger output.
|
||||||
|
func SetOutput(out io.Writer) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Out = out
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormatter sets the standard logger formatter.
|
||||||
|
func SetFormatter(formatter Formatter) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Formatter = formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook adds a hook to the standard logger hooks.
|
||||||
|
func AddHook(hook Hook) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||||
|
func WithError(err error) *Entry {
|
||||||
|
return std.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithField(key string, value interface{}) *Entry {
|
||||||
|
return std.WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFields creates an entry from the standard logger and adds multiple
|
||||||
|
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||||
|
// once for each field.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithFields(fields Fields) *Entry {
|
||||||
|
return std.WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
|
func Debug(args ...interface{}) {
|
||||||
|
std.Debug(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print logs a message at level Info on the standard logger.
|
||||||
|
func Print(args ...interface{}) {
|
||||||
|
std.Print(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info logs a message at level Info on the standard logger.
|
||||||
|
func Info(args ...interface{}) {
|
||||||
|
std.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn logs a message at level Warn on the standard logger.
|
||||||
|
func Warn(args ...interface{}) {
|
||||||
|
std.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning logs a message at level Warn on the standard logger.
|
||||||
|
func Warning(args ...interface{}) {
|
||||||
|
std.Warning(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs a message at level Error on the standard logger.
|
||||||
|
func Error(args ...interface{}) {
|
||||||
|
std.Error(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic logs a message at level Panic on the standard logger.
|
||||||
|
func Panic(args ...interface{}) {
|
||||||
|
std.Panic(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatal(args ...interface{}) {
|
||||||
|
std.Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs a message at level Debug on the standard logger.
|
||||||
|
func Debugf(format string, args ...interface{}) {
|
||||||
|
std.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf logs a message at level Info on the standard logger.
|
||||||
|
func Printf(format string, args ...interface{}) {
|
||||||
|
std.Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a message at level Info on the standard logger.
|
||||||
|
func Infof(format string, args ...interface{}) {
|
||||||
|
std.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a message at level Warn on the standard logger.
|
||||||
|
func Warnf(format string, args ...interface{}) {
|
||||||
|
std.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningf logs a message at level Warn on the standard logger.
|
||||||
|
func Warningf(format string, args ...interface{}) {
|
||||||
|
std.Warningf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a message at level Error on the standard logger.
|
||||||
|
func Errorf(format string, args ...interface{}) {
|
||||||
|
std.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicf logs a message at level Panic on the standard logger.
|
||||||
|
func Panicf(format string, args ...interface{}) {
|
||||||
|
std.Panicf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalf logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalf(format string, args ...interface{}) {
|
||||||
|
std.Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugln logs a message at level Debug on the standard logger.
|
||||||
|
func Debugln(args ...interface{}) {
|
||||||
|
std.Debugln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println logs a message at level Info on the standard logger.
|
||||||
|
func Println(args ...interface{}) {
|
||||||
|
std.Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infoln logs a message at level Info on the standard logger.
|
||||||
|
func Infoln(args ...interface{}) {
|
||||||
|
std.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnln logs a message at level Warn on the standard logger.
|
||||||
|
func Warnln(args ...interface{}) {
|
||||||
|
std.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningln logs a message at level Warn on the standard logger.
|
||||||
|
func Warningln(args ...interface{}) {
|
||||||
|
std.Warningln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorln logs a message at level Error on the standard logger.
|
||||||
|
func Errorln(args ...interface{}) {
|
||||||
|
std.Errorln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicln logs a message at level Panic on the standard logger.
|
||||||
|
func Panicln(args ...interface{}) {
|
||||||
|
std.Panicln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalln logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalln(args ...interface{}) {
|
||||||
|
std.Fatalln(args...)
|
||||||
|
}
|
45
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
45
vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const DefaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
|
//
|
||||||
|
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||||
|
// * `entry.Data["time"]`. The timestamp.
|
||||||
|
// * `entry.Data["level"]. The level the entry was logged at.
|
||||||
|
//
|
||||||
|
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||||
|
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||||
|
// logged to `logger.Out`.
|
||||||
|
type Formatter interface {
|
||||||
|
Format(*Entry) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||||
|
// dumping it. If this code wasn't there doing:
|
||||||
|
//
|
||||||
|
// logrus.WithField("level", 1).Info("hello")
|
||||||
|
//
|
||||||
|
// Would just silently drop the user provided level. Instead with this code
|
||||||
|
// it'll logged as:
|
||||||
|
//
|
||||||
|
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, ok := data["msg"]; ok {
|
||||||
|
data["fields.msg"] = m
|
||||||
|
}
|
||||||
|
|
||||||
|
if l, ok := data["level"]; ok {
|
||||||
|
data["fields.level"] = l
|
||||||
|
}
|
||||||
|
}
|
101
vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
Normal file
101
vendor/github.com/Sirupsen/logrus/formatter_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// smallFields is a small size data set for benchmarking
|
||||||
|
var smallFields = Fields{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "qux",
|
||||||
|
"one": "two",
|
||||||
|
"three": "four",
|
||||||
|
}
|
||||||
|
|
||||||
|
// largeFields is a large size data set for benchmarking
|
||||||
|
var largeFields = Fields{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "qux",
|
||||||
|
"one": "two",
|
||||||
|
"three": "four",
|
||||||
|
"five": "six",
|
||||||
|
"seven": "eight",
|
||||||
|
"nine": "ten",
|
||||||
|
"eleven": "twelve",
|
||||||
|
"thirteen": "fourteen",
|
||||||
|
"fifteen": "sixteen",
|
||||||
|
"seventeen": "eighteen",
|
||||||
|
"nineteen": "twenty",
|
||||||
|
"a": "b",
|
||||||
|
"c": "d",
|
||||||
|
"e": "f",
|
||||||
|
"g": "h",
|
||||||
|
"i": "j",
|
||||||
|
"k": "l",
|
||||||
|
"m": "n",
|
||||||
|
"o": "p",
|
||||||
|
"q": "r",
|
||||||
|
"s": "t",
|
||||||
|
"u": "v",
|
||||||
|
"w": "x",
|
||||||
|
"y": "z",
|
||||||
|
"this": "will",
|
||||||
|
"make": "thirty",
|
||||||
|
"entries": "yeah",
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorFields = Fields{
|
||||||
|
"foo": fmt.Errorf("bar"),
|
||||||
|
"baz": fmt.Errorf("qux"),
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkErrorTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSmallTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLargeTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSmallColoredTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLargeColoredTextFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSmallJSONFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &JSONFormatter{}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLargeJSONFormatter(b *testing.B) {
|
||||||
|
doBenchmark(b, &JSONFormatter{}, largeFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doBenchmark(b *testing.B, formatter Formatter, fields Fields) {
|
||||||
|
logger := New()
|
||||||
|
|
||||||
|
entry := &Entry{
|
||||||
|
Time: time.Time{},
|
||||||
|
Level: InfoLevel,
|
||||||
|
Message: "message",
|
||||||
|
Data: fields,
|
||||||
|
Logger: logger,
|
||||||
|
}
|
||||||
|
var d []byte
|
||||||
|
var err error
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
d, err = formatter.Format(entry)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
b.SetBytes(int64(len(d)))
|
||||||
|
}
|
||||||
|
}
|
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
Normal file
122
vendor/github.com/Sirupsen/logrus/hook_test.go
generated
vendored
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TestHook struct {
|
||||||
|
Fired bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *TestHook) Fire(entry *Entry) error {
|
||||||
|
hook.Fired = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *TestHook) Levels() []Level {
|
||||||
|
return []Level{
|
||||||
|
DebugLevel,
|
||||||
|
InfoLevel,
|
||||||
|
WarnLevel,
|
||||||
|
ErrorLevel,
|
||||||
|
FatalLevel,
|
||||||
|
PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookFires(t *testing.T) {
|
||||||
|
hook := new(TestHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
assert.Equal(t, hook.Fired, false)
|
||||||
|
|
||||||
|
log.Print("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, hook.Fired, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyHook struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ModifyHook) Fire(entry *Entry) error {
|
||||||
|
entry.Data["wow"] = "whale"
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ModifyHook) Levels() []Level {
|
||||||
|
return []Level{
|
||||||
|
DebugLevel,
|
||||||
|
InfoLevel,
|
||||||
|
WarnLevel,
|
||||||
|
ErrorLevel,
|
||||||
|
FatalLevel,
|
||||||
|
PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHookCanModifyEntry(t *testing.T) {
|
||||||
|
hook := new(ModifyHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
log.WithField("wow", "elephant").Print("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["wow"], "whale")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCanFireMultipleHooks(t *testing.T) {
|
||||||
|
hook1 := new(ModifyHook)
|
||||||
|
hook2 := new(TestHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook1)
|
||||||
|
log.Hooks.Add(hook2)
|
||||||
|
|
||||||
|
log.WithField("wow", "elephant").Print("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["wow"], "whale")
|
||||||
|
assert.Equal(t, hook2.Fired, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorHook struct {
|
||||||
|
Fired bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ErrorHook) Fire(entry *Entry) error {
|
||||||
|
hook.Fired = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *ErrorHook) Levels() []Level {
|
||||||
|
return []Level{
|
||||||
|
ErrorLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorHookShouldntFireOnInfo(t *testing.T) {
|
||||||
|
hook := new(ErrorHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
log.Info("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, hook.Fired, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorHookShouldFireOnError(t *testing.T) {
|
||||||
|
hook := new(ErrorHook)
|
||||||
|
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
log.Error("test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, hook.Fired, true)
|
||||||
|
})
|
||||||
|
}
|
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
34
vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
// A hook to be fired when logging on the logging levels returned from
|
||||||
|
// `Levels()` on your implementation of the interface. Note that this is not
|
||||||
|
// fired in a goroutine or a channel with workers, you should handle such
|
||||||
|
// functionality yourself if your call is non-blocking and you don't wish for
|
||||||
|
// the logging calls for levels returned from `Levels()` to block.
|
||||||
|
type Hook interface {
|
||||||
|
Levels() []Level
|
||||||
|
Fire(*Entry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal type for storing the hooks on a logger instance.
|
||||||
|
type LevelHooks map[Level][]Hook
|
||||||
|
|
||||||
|
// Add a hook to an instance of logger. This is called with
|
||||||
|
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||||
|
func (hooks LevelHooks) Add(hook Hook) {
|
||||||
|
for _, level := range hook.Levels() {
|
||||||
|
hooks[level] = append(hooks[level], hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||||
|
// appropriate hooks for a log entry.
|
||||||
|
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
||||||
|
for _, hook := range hooks[level] {
|
||||||
|
if err := hook.Fire(entry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
39
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
Normal file
39
vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
54
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
Normal file
54
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// +build !windows,!nacl,!plan9
|
||||||
|
|
||||||
|
package logrus_syslog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"log/syslog"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SyslogHook to send logs via syslog.
|
||||||
|
type SyslogHook struct {
|
||||||
|
Writer *syslog.Writer
|
||||||
|
SyslogNetwork string
|
||||||
|
SyslogRaddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a hook to be added to an instance of logger. This is called with
|
||||||
|
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
|
||||||
|
// `if err == nil { log.Hooks.Add(hook) }`
|
||||||
|
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
|
||||||
|
w, err := syslog.Dial(network, raddr, priority, tag)
|
||||||
|
return &SyslogHook{w, network, raddr}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
||||||
|
line, err := entry.String()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch entry.Level {
|
||||||
|
case logrus.PanicLevel:
|
||||||
|
return hook.Writer.Crit(line)
|
||||||
|
case logrus.FatalLevel:
|
||||||
|
return hook.Writer.Crit(line)
|
||||||
|
case logrus.ErrorLevel:
|
||||||
|
return hook.Writer.Err(line)
|
||||||
|
case logrus.WarnLevel:
|
||||||
|
return hook.Writer.Warning(line)
|
||||||
|
case logrus.InfoLevel:
|
||||||
|
return hook.Writer.Info(line)
|
||||||
|
case logrus.DebugLevel:
|
||||||
|
return hook.Writer.Debug(line)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *SyslogHook) Levels() []logrus.Level {
|
||||||
|
return logrus.AllLevels
|
||||||
|
}
|
26
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
Normal file
26
vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package logrus_syslog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"log/syslog"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLocalhostAddAndPrint(t *testing.T) {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Unable to connect to local syslog.")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
|
||||||
|
for _, level := range hook.Levels() {
|
||||||
|
if len(log.Hooks[level]) != 1 {
|
||||||
|
t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Congratulations!")
|
||||||
|
}
|
95
vendor/github.com/Sirupsen/logrus/hooks/test/test.go
generated
vendored
Normal file
95
vendor/github.com/Sirupsen/logrus/hooks/test/test.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// The Test package is used for testing logrus. It is here for backwards
|
||||||
|
// compatibility from when logrus' organization was upper-case. Please use
|
||||||
|
// lower-case logrus and the `null` package instead of this one.
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hook is a hook designed for dealing with logs in test scenarios.
|
||||||
|
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
|
||||||
|
mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGlobal installs a test hook for the global logger.
|
||||||
|
func NewGlobal() *Hook {
|
||||||
|
|
||||||
|
hook := new(Hook)
|
||||||
|
logrus.AddHook(hook)
|
||||||
|
|
||||||
|
return hook
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLocal installs a test hook for a given local logger.
|
||||||
|
func NewLocal(logger *logrus.Logger) *Hook {
|
||||||
|
|
||||||
|
hook := new(Hook)
|
||||||
|
logger.Hooks.Add(hook)
|
||||||
|
|
||||||
|
return hook
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNullLogger creates a discarding logger and installs the test hook.
|
||||||
|
func NewNullLogger() (*logrus.Logger, *Hook) {
|
||||||
|
|
||||||
|
logger := logrus.New()
|
||||||
|
logger.Out = ioutil.Discard
|
||||||
|
|
||||||
|
return logger, NewLocal(logger)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Hook) Fire(e *logrus.Entry) error {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
t.Entries = append(t.Entries, e)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Hook) Levels() []logrus.Level {
|
||||||
|
return logrus.AllLevels
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastEntry returns the last entry that was logged or nil.
|
||||||
|
func (t *Hook) LastEntry() *logrus.Entry {
|
||||||
|
t.mu.RLock()
|
||||||
|
defer t.mu.RUnlock()
|
||||||
|
i := len(t.Entries) - 1
|
||||||
|
if i < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Make a copy, for safety
|
||||||
|
e := *t.Entries[i]
|
||||||
|
return &e
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllEntries returns all entries that were logged.
|
||||||
|
func (t *Hook) AllEntries() []*logrus.Entry {
|
||||||
|
t.mu.RLock()
|
||||||
|
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 {
|
||||||
|
// Make a copy, for safety
|
||||||
|
e := *entry
|
||||||
|
entries[i] = &e
|
||||||
|
}
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset removes all Entries from this test hook.
|
||||||
|
func (t *Hook) Reset() {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
t.Entries = make([]*logrus.Entry, 0)
|
||||||
|
}
|
39
vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
generated
vendored
Normal file
39
vendor/github.com/Sirupsen/logrus/hooks/test/test_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAllHooks(t *testing.T) {
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
logger, hook := NewNullLogger()
|
||||||
|
assert.Nil(hook.LastEntry())
|
||||||
|
assert.Equal(0, len(hook.Entries))
|
||||||
|
|
||||||
|
logger.Error("Hello error")
|
||||||
|
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||||
|
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||||
|
assert.Equal(1, len(hook.Entries))
|
||||||
|
|
||||||
|
logger.Warn("Hello warning")
|
||||||
|
assert.Equal(logrus.WarnLevel, hook.LastEntry().Level)
|
||||||
|
assert.Equal("Hello warning", hook.LastEntry().Message)
|
||||||
|
assert.Equal(2, len(hook.Entries))
|
||||||
|
|
||||||
|
hook.Reset()
|
||||||
|
assert.Nil(hook.LastEntry())
|
||||||
|
assert.Equal(0, len(hook.Entries))
|
||||||
|
|
||||||
|
hook = NewGlobal()
|
||||||
|
|
||||||
|
logrus.Error("Hello error")
|
||||||
|
assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level)
|
||||||
|
assert.Equal("Hello error", hook.LastEntry().Message)
|
||||||
|
assert.Equal(1, len(hook.Entries))
|
||||||
|
|
||||||
|
}
|
74
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
74
vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fieldKey string
|
||||||
|
type FieldMap map[fieldKey]string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FieldKeyMsg = "msg"
|
||||||
|
FieldKeyLevel = "level"
|
||||||
|
FieldKeyTime = "time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f FieldMap) resolve(key fieldKey) string {
|
||||||
|
if k, ok := f[key]; ok {
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
type JSONFormatter struct {
|
||||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
|
// DisableTimestamp allows disabling automatic timestamps in output
|
||||||
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// FieldMap allows users to customize the names of keys for various fields.
|
||||||
|
// As an example:
|
||||||
|
// formatter := &JSONFormatter{
|
||||||
|
// FieldMap: FieldMap{
|
||||||
|
// FieldKeyTime: "@timestamp",
|
||||||
|
// FieldKeyLevel: "@level",
|
||||||
|
// FieldKeyMsg: "@message",
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
FieldMap FieldMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
data := make(Fields, len(entry.Data)+3)
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case error:
|
||||||
|
// Otherwise errors are ignored by `encoding/json`
|
||||||
|
// https://github.com/sirupsen/logrus/issues/137
|
||||||
|
data[k] = v.Error()
|
||||||
|
default:
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefixFieldClashes(data)
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
199
vendor/github.com/Sirupsen/logrus/json_formatter_test.go
generated
vendored
Normal file
199
vendor/github.com/Sirupsen/logrus/json_formatter_test.go
generated
vendored
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestErrorNotLost(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
|
||||||
|
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["error"] != "wild walrus" {
|
||||||
|
t.Fatal("Error field not set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
|
||||||
|
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["omg"] != "wild walrus" {
|
||||||
|
t.Fatal("Error field not set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFieldClashWithTime(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("time", "right now!"))
|
||||||
|
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.time"] != "right now!" {
|
||||||
|
t.Fatal("fields.time not set to original time field")
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry["time"] != "0001-01-01T00:00:00Z" {
|
||||||
|
t.Fatal("time field not set to current time, was: ", entry["time"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFieldClashWithMsg(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("msg", "something"))
|
||||||
|
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.msg"] != "something" {
|
||||||
|
t.Fatal("fields.msg not set to original msg field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFieldClashWithLevel(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("level", "something"))
|
||||||
|
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.level"] != "something" {
|
||||||
|
t.Fatal("fields.level not set to original level field")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONEntryEndsWithNewline(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("level", "something"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Unable to format entry: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[len(b)-1] != '\n' {
|
||||||
|
t.Fatal("Expected JSON log entry to end with a newline")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONMessageKey(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{
|
||||||
|
FieldMap: FieldMap{
|
||||||
|
FieldKeyMsg: "message",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := formatter.Format(&Entry{Message: "oh hai"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Unable to format entry: ", err)
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
|
if !(strings.Contains(s, "message") && strings.Contains(s, "oh hai")) {
|
||||||
|
t.Fatal("Expected JSON to format message key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONLevelKey(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{
|
||||||
|
FieldMap: FieldMap{
|
||||||
|
FieldKeyLevel: "somelevel",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("level", "something"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Unable to format entry: ", err)
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
|
if !strings.Contains(s, "somelevel") {
|
||||||
|
t.Fatal("Expected JSON to format level key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONTimeKey(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{
|
||||||
|
FieldMap: FieldMap{
|
||||||
|
FieldKeyTime: "timeywimey",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("level", "something"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Unable to format entry: ", err)
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
|
if !strings.Contains(s, "timeywimey") {
|
||||||
|
t.Fatal("Expected JSON to format time key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONDisableTimestamp(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{
|
||||||
|
DisableTimestamp: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("level", "something"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Unable to format entry: ", err)
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
|
if strings.Contains(s, FieldKeyTime) {
|
||||||
|
t.Error("Did not prevent timestamp", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJSONEnableTimestamp(t *testing.T) {
|
||||||
|
formatter := &JSONFormatter{}
|
||||||
|
|
||||||
|
b, err := formatter.Format(WithField("level", "something"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Unable to format entry: ", err)
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
|
if !strings.Contains(s, FieldKeyTime) {
|
||||||
|
t.Error("Timestamp not present", s)
|
||||||
|
}
|
||||||
|
}
|
317
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
317
vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
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.
|
||||||
|
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
|
||||||
|
// service, log to StatsD or dump the core on fatal errors.
|
||||||
|
Hooks LevelHooks
|
||||||
|
// All log entries pass through the formatter before logged to Out. The
|
||||||
|
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||||
|
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||||
|
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||||
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||||
|
// formatters for examples.
|
||||||
|
Formatter Formatter
|
||||||
|
// 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. `logrus.Debug` is useful in
|
||||||
|
Level Level
|
||||||
|
// Used to sync writing to the log. Locking is enabled by Default
|
||||||
|
mu MutexWrap
|
||||||
|
// Reusable empty entry
|
||||||
|
entryPool sync.Pool
|
||||||
|
}
|
||||||
|
|
||||||
|
type MutexWrap struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
disabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mw *MutexWrap) Lock() {
|
||||||
|
if !mw.disabled {
|
||||||
|
mw.lock.Lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mw *MutexWrap) Unlock() {
|
||||||
|
if !mw.disabled {
|
||||||
|
mw.lock.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mw *MutexWrap) Disable() {
|
||||||
|
mw.disabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||||
|
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||||
|
// instantiate your own:
|
||||||
|
//
|
||||||
|
// var log = &Logger{
|
||||||
|
// Out: os.Stderr,
|
||||||
|
// Formatter: new(JSONFormatter),
|
||||||
|
// Hooks: make(LevelHooks),
|
||||||
|
// Level: logrus.DebugLevel,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) newEntry() *Entry {
|
||||||
|
entry, ok := logger.entryPool.Get().(*Entry)
|
||||||
|
if ok {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
return NewEntry(logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) releaseEntry(entry *Entry) {
|
||||||
|
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.
|
||||||
|
// If you want multiple fields, use `WithFields`.
|
||||||
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||||
|
// each `Field`.
|
||||||
|
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an error as single field to the log entry. All it does is call
|
||||||
|
// `WithError` for the given `error`.
|
||||||
|
func (logger *Logger) WithError(err error) *Entry {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
defer logger.releaseEntry(entry)
|
||||||
|
return entry.WithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
|
if logger.level() >= DebugLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Debugf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
|
if logger.level() >= InfoLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Infof(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Printf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
|
if logger.level() >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
|
if logger.level() >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
|
if logger.level() >= ErrorLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Errorf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
|
if logger.level() >= FatalLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Fatalf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
|
if logger.level() >= PanicLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Panicf(format, args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
|
if logger.level() >= DebugLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Debug(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
if logger.level() >= InfoLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Info(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Info(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
|
if logger.level() >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warn(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
|
if logger.level() >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warn(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
|
if logger.level() >= ErrorLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Error(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
|
if logger.level() >= FatalLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Fatal(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
|
if logger.level() >= PanicLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Panic(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
|
if logger.level() >= DebugLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Debugln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
|
if logger.level() >= InfoLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Infoln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Println(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
|
if logger.level() >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
|
if logger.level() >= WarnLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Warnln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
if logger.level() >= ErrorLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Errorln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
|
if logger.level() >= FatalLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Fatalln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
|
if logger.level() >= PanicLevel {
|
||||||
|
entry := logger.newEntry()
|
||||||
|
entry.Panicln(args...)
|
||||||
|
logger.releaseEntry(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//When file is opened with appending mode, it's safe to
|
||||||
|
//write concurrently to a file (within 4k message on Linux).
|
||||||
|
//In these cases user can choose to disable the lock.
|
||||||
|
func (logger *Logger) SetNoLock() {
|
||||||
|
logger.mu.Disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) level() Level {
|
||||||
|
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) setLevel(level Level) {
|
||||||
|
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
||||||
|
}
|
61
vendor/github.com/Sirupsen/logrus/logger_bench_test.go
generated
vendored
Normal file
61
vendor/github.com/Sirupsen/logrus/logger_bench_test.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// smallFields is a small size data set for benchmarking
|
||||||
|
var loggerFields = Fields{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "qux",
|
||||||
|
"one": "two",
|
||||||
|
"three": "four",
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDummyLogger(b *testing.B) {
|
||||||
|
nullf, err := os.OpenFile("/dev/null", os.O_WRONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
defer nullf.Close()
|
||||||
|
doLoggerBenchmark(b, nullf, &TextFormatter{DisableColors: true}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDummyLoggerNoLock(b *testing.B) {
|
||||||
|
nullf, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
defer nullf.Close()
|
||||||
|
doLoggerBenchmarkNoLock(b, nullf, &TextFormatter{DisableColors: true}, smallFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doLoggerBenchmark(b *testing.B, out *os.File, formatter Formatter, fields Fields) {
|
||||||
|
logger := Logger{
|
||||||
|
Out: out,
|
||||||
|
Level: InfoLevel,
|
||||||
|
Formatter: formatter,
|
||||||
|
}
|
||||||
|
entry := logger.WithFields(fields)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
entry.Info("aaa")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func doLoggerBenchmarkNoLock(b *testing.B, out *os.File, formatter Formatter, fields Fields) {
|
||||||
|
logger := Logger{
|
||||||
|
Out: out,
|
||||||
|
Level: InfoLevel,
|
||||||
|
Formatter: formatter,
|
||||||
|
}
|
||||||
|
logger.SetNoLock()
|
||||||
|
entry := logger.WithFields(fields)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
entry.Info("aaa")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
143
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
143
vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fields type, used to pass to `WithFields`.
|
||||||
|
type Fields map[string]interface{}
|
||||||
|
|
||||||
|
// Level type
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||||
|
func ParseLevel(lvl string) (Level, error) {
|
||||||
|
switch strings.ToLower(lvl) {
|
||||||
|
case "panic":
|
||||||
|
return PanicLevel, nil
|
||||||
|
case "fatal":
|
||||||
|
return FatalLevel, nil
|
||||||
|
case "error":
|
||||||
|
return ErrorLevel, nil
|
||||||
|
case "warn", "warning":
|
||||||
|
return WarnLevel, nil
|
||||||
|
case "info":
|
||||||
|
return InfoLevel, nil
|
||||||
|
case "debug":
|
||||||
|
return DebugLevel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var l Level
|
||||||
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A constant exposing all logging levels
|
||||||
|
var AllLevels = []Level{
|
||||||
|
PanicLevel,
|
||||||
|
FatalLevel,
|
||||||
|
ErrorLevel,
|
||||||
|
WarnLevel,
|
||||||
|
InfoLevel,
|
||||||
|
DebugLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the different logging levels. You can set the logging level to log
|
||||||
|
// on your instance of logger, obtained with `logrus.New()`.
|
||||||
|
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
|
||||||
|
// logging level is set to Panic.
|
||||||
|
FatalLevel
|
||||||
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||||
|
// Commonly used for hooks to send errors to an error tracking service.
|
||||||
|
ErrorLevel
|
||||||
|
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||||
|
WarnLevel
|
||||||
|
// InfoLevel level. General operational entries about what's going on inside the
|
||||||
|
// application.
|
||||||
|
InfoLevel
|
||||||
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||||
|
DebugLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
|
var (
|
||||||
|
_ StdLogger = &log.Logger{}
|
||||||
|
_ StdLogger = &Entry{}
|
||||||
|
_ StdLogger = &Logger{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// StdLogger is what your logrus-enabled library should take, that way
|
||||||
|
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||||
|
// interface, this is the closest we get, unfortunately.
|
||||||
|
type StdLogger interface {
|
||||||
|
Print(...interface{})
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
Println(...interface{})
|
||||||
|
|
||||||
|
Fatal(...interface{})
|
||||||
|
Fatalf(string, ...interface{})
|
||||||
|
Fatalln(...interface{})
|
||||||
|
|
||||||
|
Panic(...interface{})
|
||||||
|
Panicf(string, ...interface{})
|
||||||
|
Panicln(...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// The FieldLogger interface generalizes the Entry and Logger types
|
||||||
|
type FieldLogger interface {
|
||||||
|
WithField(key string, value interface{}) *Entry
|
||||||
|
WithFields(fields Fields) *Entry
|
||||||
|
WithError(err error) *Entry
|
||||||
|
|
||||||
|
Debugf(format string, args ...interface{})
|
||||||
|
Infof(format string, args ...interface{})
|
||||||
|
Printf(format string, args ...interface{})
|
||||||
|
Warnf(format string, args ...interface{})
|
||||||
|
Warningf(format string, args ...interface{})
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
Fatalf(format string, args ...interface{})
|
||||||
|
Panicf(format string, args ...interface{})
|
||||||
|
|
||||||
|
Debug(args ...interface{})
|
||||||
|
Info(args ...interface{})
|
||||||
|
Print(args ...interface{})
|
||||||
|
Warn(args ...interface{})
|
||||||
|
Warning(args ...interface{})
|
||||||
|
Error(args ...interface{})
|
||||||
|
Fatal(args ...interface{})
|
||||||
|
Panic(args ...interface{})
|
||||||
|
|
||||||
|
Debugln(args ...interface{})
|
||||||
|
Infoln(args ...interface{})
|
||||||
|
Println(args ...interface{})
|
||||||
|
Warnln(args ...interface{})
|
||||||
|
Warningln(args ...interface{})
|
||||||
|
Errorln(args ...interface{})
|
||||||
|
Fatalln(args ...interface{})
|
||||||
|
Panicln(args ...interface{})
|
||||||
|
}
|
386
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
Normal file
386
vendor/github.com/Sirupsen/logrus/logrus_test.go
generated
vendored
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LogAndAssertJSON(t *testing.T, log func(*Logger), assertions func(fields Fields)) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
var fields Fields
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = new(JSONFormatter)
|
||||||
|
|
||||||
|
log(logger)
|
||||||
|
|
||||||
|
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assertions(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogAndAssertText(t *testing.T, log func(*Logger), assertions func(fields map[string]string)) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = &TextFormatter{
|
||||||
|
DisableColors: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
log(logger)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfolnShouldAddSpacesBetweenStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln("test", "test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test test")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfolnShouldAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln("test", 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test 10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfolnShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln(10, 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "10 10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfoShouldAddSpacesBetweenTwoNonStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Infoln(10, 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "10 10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfoShouldNotAddSpacesBetweenStringAndNonstring(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Info("test", 10)
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "test10")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInfoShouldNotAddSpacesBetweenStrings(t *testing.T) {
|
||||||
|
LogAndAssertJSON(t, func(log *Logger) {
|
||||||
|
log.Info("test", "test")
|
||||||
|
}, func(fields Fields) {
|
||||||
|
assert.Equal(t, fields["msg"], "testtest")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithFieldsShouldAllowAssignments(t *testing.T) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
var fields Fields
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = new(JSONFormatter)
|
||||||
|
|
||||||
|
localLog := logger.WithFields(Fields{
|
||||||
|
"key1": "value1",
|
||||||
|
})
|
||||||
|
|
||||||
|
localLog.WithField("key2", "value2").Info("test")
|
||||||
|
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "value2", fields["key2"])
|
||||||
|
assert.Equal(t, "value1", fields["key1"])
|
||||||
|
|
||||||
|
buffer = bytes.Buffer{}
|
||||||
|
fields = Fields{}
|
||||||
|
localLog.Info("test")
|
||||||
|
err = json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
_, ok := fields["key2"]
|
||||||
|
assert.Equal(t, false, ok)
|
||||||
|
assert.Equal(t, "value1", fields["key1"])
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefaultFieldsAreNotPrefixed(t *testing.T) {
|
||||||
|
LogAndAssertText(t, func(log *Logger) {
|
||||||
|
ll := log.WithField("herp", "derp")
|
||||||
|
ll.Info("hello")
|
||||||
|
ll.Info("bye")
|
||||||
|
}, func(fields map[string]string) {
|
||||||
|
for _, fieldName := range []string{"fields.level", "fields.time", "fields.msg"} {
|
||||||
|
if _, ok := fields[fieldName]; ok {
|
||||||
|
t.Fatalf("should not have prefixed %q: %v", fieldName, fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDoubleLoggingDoesntPrefixPreviousFields(t *testing.T) {
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
var fields Fields
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
logger.Formatter = new(JSONFormatter)
|
||||||
|
|
||||||
|
llog := logger.WithField("context", "eating raw fish")
|
||||||
|
|
||||||
|
llog.Info("looks delicious")
|
||||||
|
|
||||||
|
err := json.Unmarshal(buffer.Bytes(), &fields)
|
||||||
|
assert.NoError(t, err, "should have decoded first message")
|
||||||
|
assert.Equal(t, len(fields), 4, "should only have msg/time/level/context fields")
|
||||||
|
assert.Equal(t, fields["msg"], "looks delicious")
|
||||||
|
assert.Equal(t, fields["context"], "eating raw fish")
|
||||||
|
|
||||||
|
buffer.Reset()
|
||||||
|
|
||||||
|
llog.Warn("omg it is!")
|
||||||
|
|
||||||
|
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.Nil(t, fields["fields.msg"], "should not have prefixed previous `msg` entry")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertLevelToString(t *testing.T) {
|
||||||
|
assert.Equal(t, "debug", DebugLevel.String())
|
||||||
|
assert.Equal(t, "info", InfoLevel.String())
|
||||||
|
assert.Equal(t, "warning", WarnLevel.String())
|
||||||
|
assert.Equal(t, "error", ErrorLevel.String())
|
||||||
|
assert.Equal(t, "fatal", FatalLevel.String())
|
||||||
|
assert.Equal(t, "panic", PanicLevel.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseLevel(t *testing.T) {
|
||||||
|
l, err := ParseLevel("panic")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, PanicLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("PANIC")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, PanicLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("fatal")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, FatalLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("FATAL")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, FatalLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("error")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, ErrorLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("ERROR")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, ErrorLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("warn")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, WarnLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("WARN")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, WarnLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("warning")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, WarnLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("WARNING")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, WarnLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("info")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, InfoLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("INFO")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, InfoLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("debug")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, DebugLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("DEBUG")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, DebugLevel, l)
|
||||||
|
|
||||||
|
l, err = ParseLevel("invalid")
|
||||||
|
assert.Equal(t, "not a valid logrus Level: \"invalid\"", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSetLevelRace(t *testing.T) {
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int) {
|
||||||
|
defer wg.Done()
|
||||||
|
if i%2 == 0 {
|
||||||
|
SetLevel(InfoLevel)
|
||||||
|
} else {
|
||||||
|
GetLevel()
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoggingRace(t *testing.T) {
|
||||||
|
logger := New()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(100)
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
go func() {
|
||||||
|
logger.Info("info")
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile test
|
||||||
|
func TestLogrusInterface(t *testing.T) {
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
fn := func(l FieldLogger) {
|
||||||
|
b := l.WithField("key", "value")
|
||||||
|
b.Debug("Test")
|
||||||
|
}
|
||||||
|
// test logger
|
||||||
|
logger := New()
|
||||||
|
logger.Out = &buffer
|
||||||
|
fn(logger)
|
||||||
|
|
||||||
|
// test Entry
|
||||||
|
e := logger.WithField("another", "value")
|
||||||
|
fn(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements io.Writer using channels for synchronization, so we can wait on
|
||||||
|
// the Entry.Writer goroutine to write in a non-racey way. This does assume that
|
||||||
|
// there is a single call to Logger.Out for each message.
|
||||||
|
type channelWriter chan []byte
|
||||||
|
|
||||||
|
func (cw channelWriter) Write(p []byte) (int, error) {
|
||||||
|
cw <- p
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEntryWriter(t *testing.T) {
|
||||||
|
cw := channelWriter(make(chan []byte, 1))
|
||||||
|
log := New()
|
||||||
|
log.Out = cw
|
||||||
|
log.Formatter = new(JSONFormatter)
|
||||||
|
log.WithField("foo", "bar").WriterLevel(WarnLevel).Write([]byte("hello\n"))
|
||||||
|
|
||||||
|
bs := <-cw
|
||||||
|
var fields Fields
|
||||||
|
err := json.Unmarshal(bs, &fields)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, fields["foo"], "bar")
|
||||||
|
assert.Equal(t, fields["level"], "warning")
|
||||||
|
}
|
10
vendor/github.com/Sirupsen/logrus/terminal_appengine.go
generated
vendored
Normal file
10
vendor/github.com/Sirupsen/logrus/terminal_appengine.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// +build appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal(f io.Writer) bool {
|
||||||
|
return true
|
||||||
|
}
|
10
vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
10
vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// +build darwin freebsd openbsd netbsd dragonfly
|
||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TIOCGETA
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
14
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
14
vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// 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 "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TCGETS
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
28
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
28
vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal(f io.Writer) bool {
|
||||||
|
var termios Termios
|
||||||
|
switch v := f.(type) {
|
||||||
|
case *os.File:
|
||||||
|
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||||
|
return err == 0
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
21
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
21
vendor/github.com/Sirupsen/logrus/terminal_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// +build solaris,!appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal(f io.Writer) bool {
|
||||||
|
switch v := f.(type) {
|
||||||
|
case *os.File:
|
||||||
|
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
|
||||||
|
return err == nil
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
82
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
82
vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 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 windows,!appengine
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
var (
|
||||||
|
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||||
|
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
enableProcessedOutput = 0x0001
|
||||||
|
enableWrapAtEolOutput = 0x0002
|
||||||
|
enableVirtualTerminalProcessing = 0x0004
|
||||||
|
)
|
||||||
|
|
||||||
|
func getVersion() (float64, error) {
|
||||||
|
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
|
||||||
|
cmd := exec.Command("cmd", "ver")
|
||||||
|
cmd.Stdout = stdout
|
||||||
|
cmd.Stderr = stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The output should be like "Microsoft Windows [Version XX.X.XXXXXX]"
|
||||||
|
version := strings.Replace(stdout.String(), "\n", "", -1)
|
||||||
|
version = strings.Replace(version, "\r\n", "", -1)
|
||||||
|
|
||||||
|
x1 := strings.Index(version, "[Version")
|
||||||
|
|
||||||
|
if x1 == -1 || strings.Index(version, "]") == -1 {
|
||||||
|
return -1, errors.New("Can't determine Windows version")
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.ParseFloat(version[x1+9:x1+13], 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ver, err := getVersion()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate Virtual Processing for Windows CMD
|
||||||
|
// Info: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||||
|
if ver >= 10 {
|
||||||
|
handle := syscall.Handle(os.Stderr.Fd())
|
||||||
|
procSetConsoleMode.Call(uintptr(handle), enableProcessedOutput|enableWrapAtEolOutput|enableVirtualTerminalProcessing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||||
|
func IsTerminal(f io.Writer) bool {
|
||||||
|
switch v := f.(type) {
|
||||||
|
case *os.File:
|
||||||
|
var st uint32
|
||||||
|
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
|
||||||
|
return r != 0 && e == 0
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
189
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
189
vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nocolor = 0
|
||||||
|
red = 31
|
||||||
|
green = 32
|
||||||
|
yellow = 33
|
||||||
|
blue = 34
|
||||||
|
gray = 37
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseTimestamp time.Time
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
baseTimestamp = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextFormatter struct {
|
||||||
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
|
ForceColors bool
|
||||||
|
|
||||||
|
// Force disabling colors.
|
||||||
|
DisableColors bool
|
||||||
|
|
||||||
|
// Disable timestamp logging. useful when output is redirected to logging
|
||||||
|
// system that already adds timestamps.
|
||||||
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||||
|
// the time passed since beginning of execution.
|
||||||
|
FullTimestamp bool
|
||||||
|
|
||||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
|
// The fields are sorted by default for a consistent output. For applications
|
||||||
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||||
|
// be desired.
|
||||||
|
DisableSorting bool
|
||||||
|
|
||||||
|
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||||
|
QuoteEmptyFields bool
|
||||||
|
|
||||||
|
// QuoteCharacter can be set to the override the default quoting character "
|
||||||
|
// with something else. For example: ', or `.
|
||||||
|
QuoteCharacter string
|
||||||
|
|
||||||
|
// Whether the logger's out is to a terminal
|
||||||
|
isTerminal bool
|
||||||
|
|
||||||
|
sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) init(entry *Entry) {
|
||||||
|
if len(f.QuoteCharacter) == 0 {
|
||||||
|
f.QuoteCharacter = "\""
|
||||||
|
}
|
||||||
|
if entry.Logger != nil {
|
||||||
|
f.isTerminal = IsTerminal(entry.Logger.Out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
var b *bytes.Buffer
|
||||||
|
keys := make([]string, 0, len(entry.Data))
|
||||||
|
for k := range entry.Data {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.DisableSorting {
|
||||||
|
sort.Strings(keys)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
if isColored {
|
||||||
|
f.printColored(b, entry, keys, 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])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte('\n')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||||
|
var levelColor int
|
||||||
|
switch entry.Level {
|
||||||
|
case DebugLevel:
|
||||||
|
levelColor = gray
|
||||||
|
case WarnLevel:
|
||||||
|
levelColor = yellow
|
||||||
|
case ErrorLevel, FatalLevel, PanicLevel:
|
||||||
|
levelColor = red
|
||||||
|
default:
|
||||||
|
levelColor = blue
|
||||||
|
}
|
||||||
|
|
||||||
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||||
|
|
||||||
|
if f.DisableTimestamp {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, 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)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
v := entry.Data[k]
|
||||||
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
|
||||||
|
f.appendValue(b, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) needsQuoting(text string) bool {
|
||||||
|
if f.QuoteEmptyFields && len(text) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, ch := range text {
|
||||||
|
if !((ch >= 'a' && ch <= 'z') ||
|
||||||
|
(ch >= 'A' && ch <= 'Z') ||
|
||||||
|
(ch >= '0' && ch <= '9') ||
|
||||||
|
ch == '-' || ch == '.') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||||
|
|
||||||
|
b.WriteString(key)
|
||||||
|
b.WriteByte('=')
|
||||||
|
f.appendValue(b, value)
|
||||||
|
b.WriteByte(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
if !f.needsQuoting(value) {
|
||||||
|
b.WriteString(value)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
|
||||||
|
}
|
||||||
|
case error:
|
||||||
|
errmsg := value.Error()
|
||||||
|
if !f.needsQuoting(errmsg) {
|
||||||
|
b.WriteString(errmsg)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Fprint(b, value)
|
||||||
|
}
|
||||||
|
}
|
87
vendor/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
Normal file
87
vendor/github.com/Sirupsen/logrus/text_formatter_test.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestQuoting(t *testing.T) {
|
||||||
|
tf := &TextFormatter{DisableColors: true}
|
||||||
|
|
||||||
|
checkQuoting := func(q bool, value interface{}) {
|
||||||
|
b, _ := tf.Format(WithField("test", value))
|
||||||
|
idx := bytes.Index(b, ([]byte)("test="))
|
||||||
|
cont := bytes.Contains(b[idx+5:], []byte(tf.QuoteCharacter))
|
||||||
|
if cont != q {
|
||||||
|
if q {
|
||||||
|
t.Errorf("quoting expected for: %#v", value)
|
||||||
|
} else {
|
||||||
|
t.Errorf("quoting not expected for: %#v", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkQuoting(false, "")
|
||||||
|
checkQuoting(false, "abcd")
|
||||||
|
checkQuoting(false, "v1.0")
|
||||||
|
checkQuoting(false, "1234567890")
|
||||||
|
checkQuoting(true, "/foobar")
|
||||||
|
checkQuoting(true, "x y")
|
||||||
|
checkQuoting(true, "x,y")
|
||||||
|
checkQuoting(false, errors.New("invalid"))
|
||||||
|
checkQuoting(true, errors.New("invalid argument"))
|
||||||
|
|
||||||
|
// Test for custom quote character.
|
||||||
|
tf.QuoteCharacter = "`"
|
||||||
|
checkQuoting(false, "")
|
||||||
|
checkQuoting(false, "abcd")
|
||||||
|
checkQuoting(true, "/foobar")
|
||||||
|
checkQuoting(true, errors.New("invalid argument"))
|
||||||
|
|
||||||
|
// Test for multi-character quotes.
|
||||||
|
tf.QuoteCharacter = "§~±"
|
||||||
|
checkQuoting(false, "abcd")
|
||||||
|
checkQuoting(true, errors.New("invalid argument"))
|
||||||
|
|
||||||
|
// Test for quoting empty fields.
|
||||||
|
tf.QuoteEmptyFields = true
|
||||||
|
checkQuoting(true, "")
|
||||||
|
checkQuoting(false, "abcd")
|
||||||
|
checkQuoting(true, errors.New("invalid argument"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimestampFormat(t *testing.T) {
|
||||||
|
checkTimeStr := func(format string) {
|
||||||
|
customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format}
|
||||||
|
customStr, _ := customFormatter.Format(WithField("test", "test"))
|
||||||
|
timeStart := bytes.Index(customStr, ([]byte)("time="))
|
||||||
|
timeEnd := bytes.Index(customStr, ([]byte)("level="))
|
||||||
|
timeStr := customStr[timeStart+5+len(customFormatter.QuoteCharacter) : timeEnd-1-len(customFormatter.QuoteCharacter)]
|
||||||
|
if format == "" {
|
||||||
|
format = time.RFC3339
|
||||||
|
}
|
||||||
|
_, e := time.Parse(format, (string)(timeStr))
|
||||||
|
if e != nil {
|
||||||
|
t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkTimeStr("2006-01-02T15:04:05.000000000Z07:00")
|
||||||
|
checkTimeStr("Mon Jan _2 15:04:05 2006")
|
||||||
|
checkTimeStr("")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDisableTimestampWithColoredOutput(t *testing.T) {
|
||||||
|
tf := &TextFormatter{DisableTimestamp: true, ForceColors: true}
|
||||||
|
|
||||||
|
b, _ := tf.Format(WithField("test", "test"))
|
||||||
|
if strings.Contains(string(b), "[0000]") {
|
||||||
|
t.Error("timestamp not expected when DisableTimestamp is true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add tests for sorting etc., this requires a parser for the text
|
||||||
|
// formatter output.
|
62
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
62
vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (logger *Logger) Writer() *io.PipeWriter {
|
||||||
|
return logger.WriterLevel(InfoLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
|
||||||
|
return NewEntry(logger).WriterLevel(level)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Writer() *io.PipeWriter {
|
||||||
|
return entry.WriterLevel(InfoLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
||||||
|
reader, writer := io.Pipe()
|
||||||
|
|
||||||
|
var printFunc func(args ...interface{})
|
||||||
|
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
printFunc = entry.Debug
|
||||||
|
case InfoLevel:
|
||||||
|
printFunc = entry.Info
|
||||||
|
case WarnLevel:
|
||||||
|
printFunc = entry.Warn
|
||||||
|
case ErrorLevel:
|
||||||
|
printFunc = entry.Error
|
||||||
|
case FatalLevel:
|
||||||
|
printFunc = entry.Fatal
|
||||||
|
case PanicLevel:
|
||||||
|
printFunc = entry.Panic
|
||||||
|
default:
|
||||||
|
printFunc = entry.Print
|
||||||
|
}
|
||||||
|
|
||||||
|
go entry.writerScanner(reader, printFunc)
|
||||||
|
runtime.SetFinalizer(writer, writerFinalizer)
|
||||||
|
|
||||||
|
return writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
for scanner.Scan() {
|
||||||
|
printFunc(scanner.Text())
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
entry.Errorf("Error while reading from Writer: %s", err)
|
||||||
|
}
|
||||||
|
reader.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func writerFinalizer(writer *io.PipeWriter) {
|
||||||
|
writer.Close()
|
||||||
|
}
|
302
vendor/golang.org/x/crypto/acme/acme.go
generated
vendored
302
vendor/golang.org/x/crypto/acme/acme.go
generated
vendored
|
@ -15,6 +15,7 @@ package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
|
@ -36,9 +37,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
"golang.org/x/net/context/ctxhttp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
|
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
|
||||||
|
@ -47,6 +45,10 @@ const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
|
||||||
const (
|
const (
|
||||||
maxChainLen = 5 // max depth and breadth of a certificate chain
|
maxChainLen = 5 // max depth and breadth of a certificate chain
|
||||||
maxCertSize = 1 << 20 // max size of a certificate, in bytes
|
maxCertSize = 1 << 20 // max size of a certificate, in bytes
|
||||||
|
|
||||||
|
// Max number of collected nonces kept in memory.
|
||||||
|
// Expect usual peak of 1 or 2.
|
||||||
|
maxNonces = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
// CertOption is an optional argument type for Client methods which manipulate
|
// CertOption is an optional argument type for Client methods which manipulate
|
||||||
|
@ -108,6 +110,9 @@ type Client struct {
|
||||||
|
|
||||||
dirMu sync.Mutex // guards writes to dir
|
dirMu sync.Mutex // guards writes to dir
|
||||||
dir *Directory // cached result of Client's Discover method
|
dir *Directory // cached result of Client's Discover method
|
||||||
|
|
||||||
|
noncesMu sync.Mutex
|
||||||
|
nonces map[string]struct{} // nonces collected from previous responses
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discover performs ACME server discovery using c.DirectoryURL.
|
// Discover performs ACME server discovery using c.DirectoryURL.
|
||||||
|
@ -126,11 +131,12 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
|
||||||
if dirURL == "" {
|
if dirURL == "" {
|
||||||
dirURL = LetsEncryptURL
|
dirURL = LetsEncryptURL
|
||||||
}
|
}
|
||||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, dirURL)
|
res, err := c.get(ctx, dirURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Directory{}, err
|
return Directory{}, err
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
c.addNonce(res.Header)
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
return Directory{}, responseError(res)
|
return Directory{}, responseError(res)
|
||||||
}
|
}
|
||||||
|
@ -146,7 +152,7 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
|
||||||
CAA []string `json:"caa-identities"`
|
CAA []string `json:"caa-identities"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if json.NewDecoder(res.Body).Decode(&v); err != nil {
|
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||||
return Directory{}, err
|
return Directory{}, err
|
||||||
}
|
}
|
||||||
c.dir = &Directory{
|
c.dir = &Directory{
|
||||||
|
@ -192,7 +198,7 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
||||||
req.NotAfter = now.Add(exp).Format(time.RFC3339)
|
req.NotAfter = now.Add(exp).Format(time.RFC3339)
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.CertURL, req)
|
res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
@ -208,7 +214,7 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
||||||
return cert, curl, err
|
return cert, curl, err
|
||||||
}
|
}
|
||||||
// slurp issued cert and CA chain, if requested
|
// slurp issued cert and CA chain, if requested
|
||||||
cert, err := responseCert(ctx, c.HTTPClient, res, bundle)
|
cert, err := c.responseCert(ctx, res, bundle)
|
||||||
return cert, curl, err
|
return cert, curl, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,13 +229,13 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
||||||
// and has expected features.
|
// and has expected features.
|
||||||
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
|
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
|
||||||
for {
|
for {
|
||||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
res, err := c.get(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
if res.StatusCode == http.StatusOK {
|
if res.StatusCode == http.StatusOK {
|
||||||
return responseCert(ctx, c.HTTPClient, res, bundle)
|
return c.responseCert(ctx, res, bundle)
|
||||||
}
|
}
|
||||||
if res.StatusCode > 299 {
|
if res.StatusCode > 299 {
|
||||||
return nil, responseError(res)
|
return nil, responseError(res)
|
||||||
|
@ -267,7 +273,7 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
|
||||||
if key == nil {
|
if key == nil {
|
||||||
key = c.Key
|
key = c.Key
|
||||||
}
|
}
|
||||||
res, err := postJWS(ctx, c.HTTPClient, key, c.dir.RevokeURL, body)
|
res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -355,7 +361,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
|
||||||
Resource: "new-authz",
|
Resource: "new-authz",
|
||||||
Identifier: authzID{Type: "dns", Value: domain},
|
Identifier: authzID{Type: "dns", Value: domain},
|
||||||
}
|
}
|
||||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.AuthzURL, req)
|
res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -379,7 +385,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
|
||||||
// If a caller needs to poll an authorization until its status is final,
|
// If a caller needs to poll an authorization until its status is final,
|
||||||
// see the WaitAuthorization method.
|
// see the WaitAuthorization method.
|
||||||
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
||||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
res, err := c.get(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -413,7 +419,7 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
|
||||||
Status: "deactivated",
|
Status: "deactivated",
|
||||||
Delete: true,
|
Delete: true,
|
||||||
}
|
}
|
||||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
|
res, err := c.retryPostJWS(ctx, c.Key, url, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -430,25 +436,11 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
|
||||||
//
|
//
|
||||||
// It returns a non-nil Authorization only if its Status is StatusValid.
|
// It returns a non-nil Authorization only if its Status is StatusValid.
|
||||||
// In all other cases WaitAuthorization returns an error.
|
// In all other cases WaitAuthorization returns an error.
|
||||||
// If the Status is StatusInvalid, the returned error is ErrAuthorizationFailed.
|
// If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
|
||||||
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
||||||
var count int
|
sleep := sleeper(ctx)
|
||||||
sleep := func(v string, inc int) error {
|
|
||||||
count += inc
|
|
||||||
d := backoff(count, 10*time.Second)
|
|
||||||
d = retryAfter(v, d)
|
|
||||||
wakeup := time.NewTimer(d)
|
|
||||||
defer wakeup.Stop()
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
case <-wakeup.C:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
res, err := c.get(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -473,7 +465,7 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
|
||||||
return raw.authorization(url), nil
|
return raw.authorization(url), nil
|
||||||
}
|
}
|
||||||
if raw.Status == StatusInvalid {
|
if raw.Status == StatusInvalid {
|
||||||
return nil, ErrAuthorizationFailed
|
return nil, raw.error(url)
|
||||||
}
|
}
|
||||||
if err := sleep(retry, 0); err != nil {
|
if err := sleep(retry, 0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -485,7 +477,7 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
|
||||||
//
|
//
|
||||||
// A client typically polls a challenge status using this method.
|
// A client typically polls a challenge status using this method.
|
||||||
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
|
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
|
||||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
res, err := c.get(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -519,7 +511,7 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error
|
||||||
Type: chal.Type,
|
Type: chal.Type,
|
||||||
Auth: auth,
|
Auth: auth,
|
||||||
}
|
}
|
||||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, chal.URI, req)
|
res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -652,7 +644,7 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
||||||
req.Contact = acct.Contact
|
req.Contact = acct.Contact
|
||||||
req.Agreement = acct.AgreedTerms
|
req.Agreement = acct.AgreedTerms
|
||||||
}
|
}
|
||||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
|
res, err := c.retryPostJWS(ctx, c.Key, url, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -689,7 +681,170 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func responseCert(ctx context.Context, client *http.Client, res *http.Response, bundle bool) ([][]byte, error) {
|
// 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.
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
var nonce string
|
||||||
|
for nonce = range c.nonces {
|
||||||
|
delete(c.nonces, nonce)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nonce, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearNonces clears any stored nonces
|
||||||
|
func (c *Client) clearNonces() {
|
||||||
|
c.noncesMu.Lock()
|
||||||
|
defer c.noncesMu.Unlock()
|
||||||
|
c.nonces = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// addNonce stores a nonce value found in h (if any) for future use.
|
||||||
|
func (c *Client) addNonce(h http.Header) {
|
||||||
|
v := nonceFromHeader(h)
|
||||||
|
if v == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.noncesMu.Lock()
|
||||||
|
defer c.noncesMu.Unlock()
|
||||||
|
if len(c.nonces) >= maxNonces {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.nonces == nil {
|
||||||
|
c.nonces = make(map[string]struct{})
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
nonce := nonceFromHeader(resp.Header)
|
||||||
|
if nonce == "" {
|
||||||
|
if resp.StatusCode > 299 {
|
||||||
|
return "", responseError(resp)
|
||||||
|
}
|
||||||
|
return "", errors.New("acme: nonce not found")
|
||||||
|
}
|
||||||
|
return nonce, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nonceFromHeader(h http.Header) string {
|
||||||
|
return h.Get("Replay-Nonce")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) {
|
||||||
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
|
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("acme: response stream: %v", err)
|
return nil, fmt.Errorf("acme: response stream: %v", err)
|
||||||
|
@ -713,7 +868,7 @@ func responseCert(ctx context.Context, client *http.Client, res *http.Response,
|
||||||
return nil, errors.New("acme: rel=up link is too large")
|
return nil, errors.New("acme: rel=up link is too large")
|
||||||
}
|
}
|
||||||
for _, url := range up {
|
for _, url := range up {
|
||||||
cc, err := chainCert(ctx, client, url, 0)
|
cc, err := c.chainCert(ctx, url, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -727,14 +882,8 @@ func responseError(resp *http.Response) error {
|
||||||
// don't care if ReadAll returns an error:
|
// don't care if ReadAll returns an error:
|
||||||
// json.Unmarshal will fail in that case anyway
|
// json.Unmarshal will fail in that case anyway
|
||||||
b, _ := ioutil.ReadAll(resp.Body)
|
b, _ := ioutil.ReadAll(resp.Body)
|
||||||
e := struct {
|
e := &wireError{Status: resp.StatusCode}
|
||||||
Status int
|
if err := json.Unmarshal(b, e); err != nil {
|
||||||
Type string
|
|
||||||
Detail string
|
|
||||||
}{
|
|
||||||
Status: resp.StatusCode,
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(b, &e); err != nil {
|
|
||||||
// this is not a regular error response:
|
// this is not a regular error response:
|
||||||
// populate detail with anything we received,
|
// populate detail with anything we received,
|
||||||
// e.Status will already contain HTTP response code value
|
// e.Status will already contain HTTP response code value
|
||||||
|
@ -743,12 +892,7 @@ func responseError(resp *http.Response) error {
|
||||||
e.Detail = resp.Status
|
e.Detail = resp.Status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Error{
|
return e.error(resp.Header)
|
||||||
StatusCode: e.Status,
|
|
||||||
ProblemType: e.Type,
|
|
||||||
Detail: e.Detail,
|
|
||||||
Header: resp.Header,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// chainCert fetches CA certificate chain recursively by following "up" links.
|
// chainCert fetches CA certificate chain recursively by following "up" links.
|
||||||
|
@ -756,12 +900,12 @@ func responseError(resp *http.Response) error {
|
||||||
// if the recursion level reaches maxChainLen.
|
// if the recursion level reaches maxChainLen.
|
||||||
//
|
//
|
||||||
// First chainCert call starts with depth of 0.
|
// First chainCert call starts with depth of 0.
|
||||||
func chainCert(ctx context.Context, client *http.Client, url string, depth int) ([][]byte, error) {
|
func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) {
|
||||||
if depth >= maxChainLen {
|
if depth >= maxChainLen {
|
||||||
return nil, errors.New("acme: certificate chain is too deep")
|
return nil, errors.New("acme: certificate chain is too deep")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := ctxhttp.Get(ctx, client, url)
|
res, err := c.get(ctx, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -783,7 +927,7 @@ func chainCert(ctx context.Context, client *http.Client, url string, depth int)
|
||||||
return nil, errors.New("acme: certificate chain is too large")
|
return nil, errors.New("acme: certificate chain is too large")
|
||||||
}
|
}
|
||||||
for _, up := range uplink {
|
for _, up := range uplink {
|
||||||
cc, err := chainCert(ctx, client, up, depth+1)
|
cc, err := c.chainCert(ctx, up, depth+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -793,33 +937,6 @@ func chainCert(ctx context.Context, client *http.Client, url string, depth int)
|
||||||
return chain, nil
|
return chain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// postJWS signs the body with the given key and POSTs it to the provided url.
|
|
||||||
// The body argument must be JSON-serializable.
|
|
||||||
func postJWS(ctx context.Context, client *http.Client, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
|
||||||
nonce, err := fetchNonce(ctx, client, url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
b, err := jwsEncodeJSON(body, key, nonce)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ctxhttp.Post(ctx, client, url, "application/jose+json", bytes.NewReader(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchNonce(ctx context.Context, client *http.Client, url string) (string, error) {
|
|
||||||
resp, err := ctxhttp.Head(ctx, client, url)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
enc := resp.Header.Get("replay-nonce")
|
|
||||||
if enc == "" {
|
|
||||||
return "", errors.New("acme: nonce not found")
|
|
||||||
}
|
|
||||||
return enc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// linkHeader returns URI-Reference values of all Link headers
|
// linkHeader returns URI-Reference values of all Link headers
|
||||||
// with relation-type rel.
|
// with relation-type rel.
|
||||||
// See https://tools.ietf.org/html/rfc5988#section-5 for details.
|
// See https://tools.ietf.org/html/rfc5988#section-5 for details.
|
||||||
|
@ -840,6 +957,28 @@ func linkHeader(h http.Header, rel string) []string {
|
||||||
return links
|
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,
|
// retryAfter parses a Retry-After HTTP header value,
|
||||||
// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
|
// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
|
||||||
// It returns d if v cannot be parsed.
|
// It returns d if v cannot be parsed.
|
||||||
|
@ -921,7 +1060,8 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
||||||
NotBefore: time.Now(),
|
NotBefore: time.Now(),
|
||||||
NotAfter: time.Now().Add(24 * time.Hour),
|
NotAfter: time.Now().Add(24 * time.Hour),
|
||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment,
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tmpl.DNSNames = san
|
tmpl.DNSNames = san
|
||||||
|
|
165
vendor/golang.org/x/crypto/acme/acme_test.go
generated
vendored
165
vendor/golang.org/x/crypto/acme/acme_test.go
generated
vendored
|
@ -6,6 +6,7 @@ package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
@ -23,8 +24,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
|
// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
|
||||||
|
@ -45,6 +44,28 @@ func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type jwsHead struct {
|
||||||
|
Alg string
|
||||||
|
Nonce string
|
||||||
|
JWK map[string]string `json:"jwk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeJWSHead(r *http.Request) (*jwsHead, error) {
|
||||||
|
var req struct{ Protected string }
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b, err := base64.RawURLEncoding.DecodeString(req.Protected)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var head jwsHead
|
||||||
|
if err := json.Unmarshal(b, &head); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &head, nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestDiscover(t *testing.T) {
|
func TestDiscover(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
reg = "https://example.com/acme/new-reg"
|
reg = "https://example.com/acme/new-reg"
|
||||||
|
@ -522,6 +543,9 @@ func TestWaitAuthorizationInvalid(t *testing.T) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("err is nil")
|
t.Error("err is nil")
|
||||||
}
|
}
|
||||||
|
if _, ok := err.(*AuthorizationError); !ok {
|
||||||
|
t.Errorf("err is %T; want *AuthorizationError", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,7 +940,30 @@ func TestRevokeCert(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetchNonce(t *testing.T) {
|
func TestNonce_add(t *testing.T) {
|
||||||
|
var c Client
|
||||||
|
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||||
|
c.addNonce(http.Header{"Replay-Nonce": {}})
|
||||||
|
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||||
|
|
||||||
|
nonces := map[string]struct{}{"nonce": struct{}{}}
|
||||||
|
if !reflect.DeepEqual(c.nonces, nonces) {
|
||||||
|
t.Errorf("c.nonces = %q; want %q", c.nonces, nonces)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNonce_addMax(t *testing.T) {
|
||||||
|
c := &Client{nonces: make(map[string]struct{})}
|
||||||
|
for i := 0; i < maxNonces; i++ {
|
||||||
|
c.nonces[fmt.Sprintf("%d", i)] = struct{}{}
|
||||||
|
}
|
||||||
|
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||||
|
if n := len(c.nonces); n != maxNonces {
|
||||||
|
t.Errorf("len(c.nonces) = %d; want %d", n, maxNonces)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNonce_fetch(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
code int
|
code int
|
||||||
nonce string
|
nonce string
|
||||||
|
@ -936,7 +983,8 @@ func TestFetchNonce(t *testing.T) {
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
for ; i < len(tests); i++ {
|
for ; i < len(tests); i++ {
|
||||||
test := tests[i]
|
test := tests[i]
|
||||||
n, err := fetchNonce(context.Background(), http.DefaultClient, ts.URL)
|
c := &Client{}
|
||||||
|
n, err := c.fetchNonce(context.Background(), ts.URL)
|
||||||
if n != test.nonce {
|
if n != test.nonce {
|
||||||
t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
|
t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
|
||||||
}
|
}
|
||||||
|
@ -949,6 +997,115 @@ func TestFetchNonce(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNonce_fetchError(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusTooManyRequests)
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
c := &Client{}
|
||||||
|
_, err := c.fetchNonce(context.Background(), ts.URL)
|
||||||
|
e, ok := err.(*Error)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("err is %T; want *Error", err)
|
||||||
|
}
|
||||||
|
if e.StatusCode != http.StatusTooManyRequests {
|
||||||
|
t.Errorf("e.StatusCode = %d; want %d", e.StatusCode, http.StatusTooManyRequests)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNonce_postJWS(t *testing.T) {
|
||||||
|
var count int
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
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 do a HEAD request
|
||||||
|
// but only to fetch the first nonce.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Make client.Authorize happy; we're not testing its result.
|
||||||
|
defer func() {
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
w.Write([]byte(`{"status":"valid"}`))
|
||||||
|
}()
|
||||||
|
|
||||||
|
head, err := decodeJWSHead(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("decodeJWSHead: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if head.Nonce == "" {
|
||||||
|
t.Error("head.Nonce is empty")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if seen[head.Nonce] {
|
||||||
|
t.Errorf("nonce is already used: %q", head.Nonce)
|
||||||
|
}
|
||||||
|
seen[head.Nonce] = true
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
|
||||||
|
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||||
|
t.Errorf("client.Authorize 1: %v", err)
|
||||||
|
}
|
||||||
|
// The second call should not generate another extra HEAD request.
|
||||||
|
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||||
|
t.Errorf("client.Authorize 2: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if count != 3 {
|
||||||
|
t.Errorf("total requests count: %d; want 3", count)
|
||||||
|
}
|
||||||
|
if n := len(client.nonces); n != 1 {
|
||||||
|
t.Errorf("len(client.nonces) = %d; want 1", n)
|
||||||
|
}
|
||||||
|
for k := range seen {
|
||||||
|
if _, exist := client.nonces[k]; exist {
|
||||||
|
t.Errorf("used nonce %q in client.nonces", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
func TestLinkHeader(t *testing.T) {
|
||||||
h := http.Header{"Link": {
|
h := http.Header{"Link": {
|
||||||
`<https://example.com/acme/new-authz>;rel="next"`,
|
`<https://example.com/acme/new-authz>;rel="next"`,
|
||||||
|
|
104
vendor/golang.org/x/crypto/acme/autocert/autocert.go
generated
vendored
104
vendor/golang.org/x/crypto/acme/autocert/autocert.go
generated
vendored
|
@ -10,6 +10,7 @@ package autocert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
|
@ -30,9 +31,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/acme"
|
"golang.org/x/crypto/acme"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// createCertRetryAfter is how much time to wait before removing a failed state
|
||||||
|
// entry due to an unsuccessful createCert call.
|
||||||
|
// This is a variable instead of a const for testing.
|
||||||
|
// TODO: Consider making it configurable or an exp backoff?
|
||||||
|
var createCertRetryAfter = time.Minute
|
||||||
|
|
||||||
// pseudoRand is safe for concurrent use.
|
// pseudoRand is safe for concurrent use.
|
||||||
var pseudoRand *lockedMathRand
|
var pseudoRand *lockedMathRand
|
||||||
|
|
||||||
|
@ -41,8 +47,9 @@ func init() {
|
||||||
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
|
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptTOS always returns true to indicate the acceptance of a CA Terms of Service
|
// AcceptTOS is a Manager.Prompt function that always returns true to
|
||||||
// during account registration.
|
// indicate acceptance of the CA's Terms of Service during account
|
||||||
|
// registration.
|
||||||
func AcceptTOS(tosURL string) bool { return true }
|
func AcceptTOS(tosURL string) bool { return true }
|
||||||
|
|
||||||
// HostPolicy specifies which host names the Manager is allowed to respond to.
|
// HostPolicy specifies which host names the Manager is allowed to respond to.
|
||||||
|
@ -76,18 +83,6 @@ func defaultHostPolicy(context.Context, string) error {
|
||||||
// It obtains and refreshes certificates automatically,
|
// It obtains and refreshes certificates automatically,
|
||||||
// as well as providing them to a TLS server via tls.Config.
|
// as well as providing them to a TLS server via tls.Config.
|
||||||
//
|
//
|
||||||
// A simple usage example:
|
|
||||||
//
|
|
||||||
// m := autocert.Manager{
|
|
||||||
// Prompt: autocert.AcceptTOS,
|
|
||||||
// HostPolicy: autocert.HostWhitelist("example.org"),
|
|
||||||
// }
|
|
||||||
// s := &http.Server{
|
|
||||||
// Addr: ":https",
|
|
||||||
// TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
|
|
||||||
// }
|
|
||||||
// s.ListenAndServeTLS("", "")
|
|
||||||
//
|
|
||||||
// To preserve issued certificates and improve overall performance,
|
// To preserve issued certificates and improve overall performance,
|
||||||
// use a cache implementation of Cache. For instance, DirCache.
|
// use a cache implementation of Cache. For instance, DirCache.
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
|
@ -123,7 +118,7 @@ type Manager struct {
|
||||||
// RenewBefore optionally specifies how early certificates should
|
// RenewBefore optionally specifies how early certificates should
|
||||||
// be renewed before they expire.
|
// be renewed before they expire.
|
||||||
//
|
//
|
||||||
// If zero, they're renewed 1 week before expiration.
|
// If zero, they're renewed 30 days before expiration.
|
||||||
RenewBefore time.Duration
|
RenewBefore time.Duration
|
||||||
|
|
||||||
// Client is used to perform low-level operations, such as account registration
|
// Client is used to perform low-level operations, such as account registration
|
||||||
|
@ -173,10 +168,23 @@ type Manager struct {
|
||||||
// The error is propagated back to the caller of GetCertificate and is user-visible.
|
// 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.
|
// This does not affect cached certs. See HostPolicy field description for more details.
|
||||||
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
|
if m.Prompt == nil {
|
||||||
|
return nil, errors.New("acme/autocert: Manager.Prompt not set")
|
||||||
|
}
|
||||||
|
|
||||||
name := hello.ServerName
|
name := hello.ServerName
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return nil, errors.New("acme/autocert: missing server name")
|
return nil, errors.New("acme/autocert: missing server name")
|
||||||
}
|
}
|
||||||
|
if !strings.Contains(strings.Trim(name, "."), ".") {
|
||||||
|
return nil, errors.New("acme/autocert: server name component count invalid")
|
||||||
|
}
|
||||||
|
if strings.ContainsAny(name, `/\`) {
|
||||||
|
return nil, errors.New("acme/autocert: server name contains invalid character")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
// check whether this is a token cert requested for TLS-SNI challenge
|
// check whether this is a token cert requested for TLS-SNI challenge
|
||||||
if strings.HasSuffix(name, ".acme.invalid") {
|
if strings.HasSuffix(name, ".acme.invalid") {
|
||||||
|
@ -185,7 +193,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||||
if cert := m.tokenCert[name]; cert != nil {
|
if cert := m.tokenCert[name]; cert != nil {
|
||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
if cert, err := m.cacheGet(name); err == nil {
|
if cert, err := m.cacheGet(ctx, name); err == nil {
|
||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
// TODO: cache error results?
|
// TODO: cache error results?
|
||||||
|
@ -194,7 +202,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||||
|
|
||||||
// regular domain
|
// regular domain
|
||||||
name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
|
name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
|
||||||
cert, err := m.cert(name)
|
cert, err := m.cert(ctx, name)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
@ -203,7 +211,6 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||||
}
|
}
|
||||||
|
|
||||||
// first-time
|
// first-time
|
||||||
ctx := context.Background() // TODO: use a deadline?
|
|
||||||
if err := m.hostPolicy()(ctx, name); err != nil {
|
if err := m.hostPolicy()(ctx, name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -211,14 +218,14 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
m.cachePut(name, cert)
|
m.cachePut(ctx, name, cert)
|
||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cert returns an existing certificate either from m.state or cache.
|
// 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
|
// If a certificate is found in cache but not in m.state, the latter will be filled
|
||||||
// with the cached value.
|
// with the cached value.
|
||||||
func (m *Manager) cert(name string) (*tls.Certificate, error) {
|
func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, error) {
|
||||||
m.stateMu.Lock()
|
m.stateMu.Lock()
|
||||||
if s, ok := m.state[name]; ok {
|
if s, ok := m.state[name]; ok {
|
||||||
m.stateMu.Unlock()
|
m.stateMu.Unlock()
|
||||||
|
@ -227,7 +234,7 @@ func (m *Manager) cert(name string) (*tls.Certificate, error) {
|
||||||
return s.tlscert()
|
return s.tlscert()
|
||||||
}
|
}
|
||||||
defer m.stateMu.Unlock()
|
defer m.stateMu.Unlock()
|
||||||
cert, err := m.cacheGet(name)
|
cert, err := m.cacheGet(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -249,12 +256,11 @@ func (m *Manager) cert(name string) (*tls.Certificate, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// cacheGet always returns a valid certificate, or an error otherwise.
|
// cacheGet always returns a valid certificate, or an error otherwise.
|
||||||
func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
// 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 m.Cache == nil {
|
if m.Cache == nil {
|
||||||
return nil, ErrCacheMiss
|
return nil, ErrCacheMiss
|
||||||
}
|
}
|
||||||
// TODO: might want to define a cache timeout on m
|
|
||||||
ctx := context.Background()
|
|
||||||
data, err := m.Cache.Get(ctx, domain)
|
data, err := m.Cache.Get(ctx, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -263,7 +269,7 @@ func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
||||||
// private
|
// private
|
||||||
priv, pub := pem.Decode(data)
|
priv, pub := pem.Decode(data)
|
||||||
if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
|
if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
|
||||||
return nil, errors.New("acme/autocert: no private key found in cache")
|
return nil, ErrCacheMiss
|
||||||
}
|
}
|
||||||
privKey, err := parsePrivateKey(priv.Bytes)
|
privKey, err := parsePrivateKey(priv.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -281,13 +287,14 @@ func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
||||||
pubDER = append(pubDER, b.Bytes)
|
pubDER = append(pubDER, b.Bytes)
|
||||||
}
|
}
|
||||||
if len(pub) > 0 {
|
if len(pub) > 0 {
|
||||||
return nil, errors.New("acme/autocert: invalid public key")
|
// Leftover content not consumed by pem.Decode. Corrupt. Ignore.
|
||||||
|
return nil, ErrCacheMiss
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify and create TLS cert
|
// verify and create TLS cert
|
||||||
leaf, err := validCert(domain, pubDER, privKey)
|
leaf, err := validCert(domain, pubDER, privKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, ErrCacheMiss
|
||||||
}
|
}
|
||||||
tlscert := &tls.Certificate{
|
tlscert := &tls.Certificate{
|
||||||
Certificate: pubDER,
|
Certificate: pubDER,
|
||||||
|
@ -297,7 +304,7 @@ func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
||||||
return tlscert, nil
|
return tlscert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) cachePut(domain string, tlscert *tls.Certificate) error {
|
func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error {
|
||||||
if m.Cache == nil {
|
if m.Cache == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -329,8 +336,6 @@ func (m *Manager) cachePut(domain string, tlscert *tls.Certificate) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: might want to define a cache timeout on m
|
|
||||||
ctx := context.Background()
|
|
||||||
return m.Cache.Put(ctx, domain, buf.Bytes())
|
return m.Cache.Put(ctx, domain, buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,6 +375,23 @@ func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certifica
|
||||||
|
|
||||||
der, leaf, err := m.authorizedCert(ctx, state.key, domain)
|
der, leaf, err := m.authorizedCert(ctx, state.key, domain)
|
||||||
if err != nil {
|
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)
|
||||||
|
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]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := validCert(domain, s.cert, s.key); err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(m.state, domain)
|
||||||
|
})
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
state.cert = der
|
state.cert = der
|
||||||
|
@ -418,7 +440,6 @@ func (m *Manager) certState(domain string) (*certState, error) {
|
||||||
// authorizedCert starts domain ownership verification process and requests a new cert upon success.
|
// authorizedCert starts domain ownership verification process and requests a new cert upon success.
|
||||||
// The key argument is the certificate private key.
|
// 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, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
|
||||||
// TODO: make m.verify retry or retry m.verify calls here
|
|
||||||
if err := m.verify(ctx, domain); err != nil {
|
if err := m.verify(ctx, domain); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -494,7 +515,7 @@ func (m *Manager) verify(ctx context.Context, domain string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m.putTokenCert(name, &cert)
|
m.putTokenCert(ctx, name, &cert)
|
||||||
defer func() {
|
defer func() {
|
||||||
// verification has ended at this point
|
// verification has ended at this point
|
||||||
// don't need token cert anymore
|
// don't need token cert anymore
|
||||||
|
@ -512,14 +533,14 @@ func (m *Manager) verify(ctx context.Context, domain string) error {
|
||||||
|
|
||||||
// putTokenCert stores the cert under the named key in both m.tokenCert map
|
// putTokenCert stores the cert under the named key in both m.tokenCert map
|
||||||
// and m.Cache.
|
// and m.Cache.
|
||||||
func (m *Manager) putTokenCert(name string, cert *tls.Certificate) {
|
func (m *Manager) putTokenCert(ctx context.Context, name string, cert *tls.Certificate) {
|
||||||
m.tokenCertMu.Lock()
|
m.tokenCertMu.Lock()
|
||||||
defer m.tokenCertMu.Unlock()
|
defer m.tokenCertMu.Unlock()
|
||||||
if m.tokenCert == nil {
|
if m.tokenCert == nil {
|
||||||
m.tokenCert = make(map[string]*tls.Certificate)
|
m.tokenCert = make(map[string]*tls.Certificate)
|
||||||
}
|
}
|
||||||
m.tokenCert[name] = cert
|
m.tokenCert[name] = cert
|
||||||
m.cachePut(name, cert)
|
m.cachePut(ctx, name, cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteTokenCert removes the token certificate for the specified domain name
|
// deleteTokenCert removes the token certificate for the specified domain name
|
||||||
|
@ -644,10 +665,10 @@ func (m *Manager) hostPolicy() HostPolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) renewBefore() time.Duration {
|
func (m *Manager) renewBefore() time.Duration {
|
||||||
if m.RenewBefore > maxRandRenew {
|
if m.RenewBefore > renewJitter {
|
||||||
return m.RenewBefore
|
return m.RenewBefore
|
||||||
}
|
}
|
||||||
return 7 * 24 * time.Hour // 1 week
|
return 720 * time.Hour // 30 days
|
||||||
}
|
}
|
||||||
|
|
||||||
// certState is ready when its mutex is unlocked for reading.
|
// certState is ready when its mutex is unlocked for reading.
|
||||||
|
@ -789,5 +810,10 @@ func (r *lockedMathRand) int63n(max int64) int64 {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// for easier testing
|
// For easier testing.
|
||||||
var timeNow = time.Now
|
var (
|
||||||
|
timeNow = time.Now
|
||||||
|
|
||||||
|
// Called when a state is removed.
|
||||||
|
testDidRemoveState = func(domain string) {}
|
||||||
|
)
|
||||||
|
|
267
vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
generated
vendored
267
vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
generated
vendored
|
@ -5,6 +5,7 @@
|
||||||
package autocert
|
package autocert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
|
@ -22,11 +23,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/acme"
|
"golang.org/x/crypto/acme"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var discoTmpl = template.Must(template.New("disco").Parse(`{
|
var discoTmpl = template.Must(template.New("disco").Parse(`{
|
||||||
|
@ -51,26 +52,44 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{
|
||||||
]
|
]
|
||||||
}`))
|
}`))
|
||||||
|
|
||||||
type memCache map[string][]byte
|
type memCache struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
keyData map[string][]byte
|
||||||
|
}
|
||||||
|
|
||||||
func (m memCache) Get(ctx context.Context, key string) ([]byte, error) {
|
func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) {
|
||||||
v, ok := m[key]
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
v, ok := m.keyData[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrCacheMiss
|
return nil, ErrCacheMiss
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m memCache) Put(ctx context.Context, key string, data []byte) error {
|
func (m *memCache) Put(ctx context.Context, key string, data []byte) error {
|
||||||
m[key] = data
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
m.keyData[key] = data
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m memCache) Delete(ctx context.Context, key string) error {
|
func (m *memCache) Delete(ctx context.Context, key string) error {
|
||||||
delete(m, key)
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
delete(m.keyData, key)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newMemCache() *memCache {
|
||||||
|
return &memCache{
|
||||||
|
keyData: make(map[string][]byte),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func dummyCert(pub interface{}, san ...string) ([]byte, error) {
|
func dummyCert(pub interface{}, san ...string) ([]byte, error) {
|
||||||
return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
|
return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
|
||||||
}
|
}
|
||||||
|
@ -124,14 +143,14 @@ func TestGetCertificate_trailingDot(t *testing.T) {
|
||||||
func TestGetCertificate_ForceRSA(t *testing.T) {
|
func TestGetCertificate_ForceRSA(t *testing.T) {
|
||||||
man := &Manager{
|
man := &Manager{
|
||||||
Prompt: AcceptTOS,
|
Prompt: AcceptTOS,
|
||||||
Cache: make(memCache),
|
Cache: newMemCache(),
|
||||||
ForceRSA: true,
|
ForceRSA: true,
|
||||||
}
|
}
|
||||||
defer man.stopRenew()
|
defer man.stopRenew()
|
||||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||||
testGetCertificate(t, man, "example.org", hello)
|
testGetCertificate(t, man, "example.org", hello)
|
||||||
|
|
||||||
cert, err := man.cacheGet("example.org")
|
cert, err := man.cacheGet(context.Background(), "example.org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("man.cacheGet: %v", err)
|
t.Fatalf("man.cacheGet: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -140,9 +159,110 @@ func TestGetCertificate_ForceRSA(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tests man.GetCertificate flow using the provided hello argument.
|
func TestGetCertificate_nilPrompt(t *testing.T) {
|
||||||
|
man := &Manager{}
|
||||||
|
defer man.stopRenew()
|
||||||
|
url, finish := startACMEServerStub(t, man, "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"}
|
||||||
|
if _, err := man.GetCertificate(hello); err == nil {
|
||||||
|
t.Error("got certificate for example.org; wanted error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCertificate_expiredCache(t *testing.T) {
|
||||||
|
// Make an expired cert and cache it.
|
||||||
|
pk, 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(),
|
||||||
|
}
|
||||||
|
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tlscert := &tls.Certificate{
|
||||||
|
Certificate: [][]byte{pub},
|
||||||
|
PrivateKey: pk,
|
||||||
|
}
|
||||||
|
|
||||||
|
man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()}
|
||||||
|
defer man.stopRenew()
|
||||||
|
if err := man.cachePut(context.Background(), "example.org", 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetCertificate_failedAttempt(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
const example = "example.org"
|
||||||
|
d := createCertRetryAfter
|
||||||
|
f := testDidRemoveState
|
||||||
|
defer func() {
|
||||||
|
createCertRetryAfter = d
|
||||||
|
testDidRemoveState = f
|
||||||
|
}()
|
||||||
|
createCertRetryAfter = 0
|
||||||
|
done := make(chan struct{})
|
||||||
|
testDidRemoveState = func(domain string) {
|
||||||
|
if domain != example {
|
||||||
|
t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example)
|
||||||
|
}
|
||||||
|
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}
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// startACMEServerStub runs an ACME server
|
||||||
// The domain argument is the expected domain name of a certificate request.
|
// The domain argument is the expected domain name of a certificate request.
|
||||||
func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) {
|
func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) {
|
||||||
// echo token-02 | shasum -a 256
|
// echo token-02 | shasum -a 256
|
||||||
// then divide result in 2 parts separated by dot
|
// then divide result in 2 parts separated by dot
|
||||||
tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
|
tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
|
||||||
|
@ -168,7 +288,7 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
|
||||||
// discovery
|
// discovery
|
||||||
case "/":
|
case "/":
|
||||||
if err := discoTmpl.Execute(w, ca.URL); err != nil {
|
if err := discoTmpl.Execute(w, ca.URL); err != nil {
|
||||||
t.Fatalf("discoTmpl: %v", err)
|
t.Errorf("discoTmpl: %v", err)
|
||||||
}
|
}
|
||||||
// client key registration
|
// client key registration
|
||||||
case "/new-reg":
|
case "/new-reg":
|
||||||
|
@ -178,7 +298,7 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
|
||||||
w.Header().Set("location", ca.URL+"/authz/1")
|
w.Header().Set("location", ca.URL+"/authz/1")
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
if err := authzTmpl.Execute(w, ca.URL); err != nil {
|
if err := authzTmpl.Execute(w, ca.URL); err != nil {
|
||||||
t.Fatalf("authzTmpl: %v", err)
|
t.Errorf("authzTmpl: %v", err)
|
||||||
}
|
}
|
||||||
// accept tls-sni-02 challenge
|
// accept tls-sni-02 challenge
|
||||||
case "/challenge/2":
|
case "/challenge/2":
|
||||||
|
@ -196,14 +316,14 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
|
||||||
b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
|
b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
|
||||||
csr, err := x509.ParseCertificateRequest(b)
|
csr, err := x509.ParseCertificateRequest(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("new-cert: CSR: %v", err)
|
t.Errorf("new-cert: CSR: %v", err)
|
||||||
}
|
}
|
||||||
if csr.Subject.CommonName != domain {
|
if csr.Subject.CommonName != domain {
|
||||||
t.Errorf("CommonName in CSR = %q; want %q", csr.Subject.CommonName, domain)
|
t.Errorf("CommonName in CSR = %q; want %q", csr.Subject.CommonName, domain)
|
||||||
}
|
}
|
||||||
der, err := dummyCert(csr.PublicKey, domain)
|
der, err := dummyCert(csr.PublicKey, domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("new-cert: dummyCert: %v", err)
|
t.Errorf("new-cert: dummyCert: %v", err)
|
||||||
}
|
}
|
||||||
chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
|
chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
|
||||||
w.Header().Set("link", chainUp)
|
w.Header().Set("link", chainUp)
|
||||||
|
@ -213,14 +333,51 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
|
||||||
case "/ca-cert":
|
case "/ca-cert":
|
||||||
der, err := dummyCert(nil, "ca")
|
der, err := dummyCert(nil, "ca")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ca-cert: dummyCert: %v", err)
|
t.Errorf("ca-cert: dummyCert: %v", err)
|
||||||
}
|
}
|
||||||
w.Write(der)
|
w.Write(der)
|
||||||
default:
|
default:
|
||||||
t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
|
t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
defer ca.Close()
|
finish = func() {
|
||||||
|
ca.Close()
|
||||||
|
|
||||||
|
// make sure token cert was removed
|
||||||
|
cancel := make(chan struct{})
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
tick := time.NewTicker(100 * time.Millisecond)
|
||||||
|
defer tick.Stop()
|
||||||
|
for {
|
||||||
|
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
|
||||||
|
if _, err := man.GetCertificate(hello); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-tick.C:
|
||||||
|
case <-cancel:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
close(cancel)
|
||||||
|
t.Error("token cert was not removed")
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ca.URL, finish
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
defer finish()
|
||||||
|
|
||||||
// use EC key to run faster on 386
|
// use EC key to run faster on 386
|
||||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||||
|
@ -229,7 +386,7 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
|
||||||
}
|
}
|
||||||
man.Client = &acme.Client{
|
man.Client = &acme.Client{
|
||||||
Key: key,
|
Key: key,
|
||||||
DirectoryURL: ca.URL,
|
DirectoryURL: url,
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulate tls.Config.GetCertificate
|
// simulate tls.Config.GetCertificate
|
||||||
|
@ -260,28 +417,10 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
|
||||||
t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
|
t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure token cert was removed
|
|
||||||
done = make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
|
|
||||||
if _, err := man.GetCertificate(hello); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
close(done)
|
|
||||||
}()
|
|
||||||
select {
|
|
||||||
case <-time.After(5 * time.Second):
|
|
||||||
t.Error("token cert was not removed")
|
|
||||||
case <-done:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountKeyCache(t *testing.T) {
|
func TestAccountKeyCache(t *testing.T) {
|
||||||
cache := make(memCache)
|
m := Manager{Cache: newMemCache()}
|
||||||
m := Manager{Cache: cache}
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
k1, err := m.accountKey(ctx)
|
k1, err := m.accountKey(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -315,13 +454,13 @@ func TestCache(t *testing.T) {
|
||||||
PrivateKey: privKey,
|
PrivateKey: privKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
cache := make(memCache)
|
man := &Manager{Cache: newMemCache()}
|
||||||
man := &Manager{Cache: cache}
|
|
||||||
defer man.stopRenew()
|
defer man.stopRenew()
|
||||||
if err := man.cachePut("example.org", tlscert); err != nil {
|
ctx := context.Background()
|
||||||
|
if err := man.cachePut(ctx, "example.org", tlscert); err != nil {
|
||||||
t.Fatalf("man.cachePut: %v", err)
|
t.Fatalf("man.cachePut: %v", err)
|
||||||
}
|
}
|
||||||
res, err := man.cacheGet("example.org")
|
res, err := man.cacheGet(ctx, "example.org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("man.cacheGet: %v", err)
|
t.Fatalf("man.cacheGet: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -421,3 +560,47 @@ func TestValidCert(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cacheGetFunc func(ctx context.Context, key string) ([]byte, error)
|
||||||
|
|
||||||
|
func (f cacheGetFunc) Get(ctx context.Context, key string) ([]byte, error) {
|
||||||
|
return f(ctx, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f cacheGetFunc) Put(ctx context.Context, key string, data []byte) error {
|
||||||
|
return fmt.Errorf("unsupported Put of %q = %q", key, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f cacheGetFunc) Delete(ctx context.Context, key string) error {
|
||||||
|
return fmt.Errorf("unsupported Delete of %q", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestManagerGetCertificateBogusSNI(t *testing.T) {
|
||||||
|
m := Manager{
|
||||||
|
Prompt: AcceptTOS,
|
||||||
|
Cache: cacheGetFunc(func(ctx context.Context, key string) ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("cache.Get of %s", key)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{"foo.com", "cache.Get of foo.com"},
|
||||||
|
{"foo.com.", "cache.Get of foo.com"},
|
||||||
|
{`a\b.com`, "acme/autocert: server name contains invalid character"},
|
||||||
|
{`a/b.com`, "acme/autocert: server name contains invalid character"},
|
||||||
|
{"", "acme/autocert: missing server name"},
|
||||||
|
{"foo", "acme/autocert: server name component count invalid"},
|
||||||
|
{".foo", "acme/autocert: server name component count invalid"},
|
||||||
|
{"foo.", "acme/autocert: server name component count invalid"},
|
||||||
|
{"fo.o", "cache.Get of fo.o"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
_, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name})
|
||||||
|
got := fmt.Sprint(err)
|
||||||
|
if got != tt.wantErr {
|
||||||
|
t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
14
vendor/golang.org/x/crypto/acme/autocert/cache.go
generated
vendored
14
vendor/golang.org/x/crypto/acme/autocert/cache.go
generated
vendored
|
@ -5,12 +5,11 @@
|
||||||
package autocert
|
package autocert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrCacheMiss is returned when a certificate is not found in cache.
|
// ErrCacheMiss is returned when a certificate is not found in cache.
|
||||||
|
@ -78,12 +77,13 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
|
||||||
if tmp, err = d.writeTempFile(name, data); err != nil {
|
if tmp, err = d.writeTempFile(name, data); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// prevent overwriting the file if the context was cancelled
|
select {
|
||||||
if ctx.Err() != nil {
|
case <-ctx.Done():
|
||||||
return // no need to set err
|
// Don't overwrite the file if the context was canceled.
|
||||||
|
default:
|
||||||
|
newName := filepath.Join(string(d), name)
|
||||||
|
err = os.Rename(tmp, newName)
|
||||||
}
|
}
|
||||||
name = filepath.Join(string(d), name)
|
|
||||||
err = os.Rename(tmp, name)
|
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
|
3
vendor/golang.org/x/crypto/acme/autocert/cache_test.go
generated
vendored
3
vendor/golang.org/x/crypto/acme/autocert/cache_test.go
generated
vendored
|
@ -5,13 +5,12 @@
|
||||||
package autocert
|
package autocert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// make sure DirCache satisfies Cache interface
|
// make sure DirCache satisfies Cache interface
|
||||||
|
|
34
vendor/golang.org/x/crypto/acme/autocert/example_test.go
generated
vendored
Normal file
34
vendor/golang.org/x/crypto/acme/autocert/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package autocert_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/acme/autocert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNewListener() {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Hello, TLS user! Your config: %+v", r.TLS)
|
||||||
|
})
|
||||||
|
log.Fatal(http.Serve(autocert.NewListener("example.com"), mux))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleManager() {
|
||||||
|
m := autocert.Manager{
|
||||||
|
Prompt: autocert.AcceptTOS,
|
||||||
|
HostPolicy: autocert.HostWhitelist("example.org"),
|
||||||
|
}
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: ":https",
|
||||||
|
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
|
||||||
|
}
|
||||||
|
s.ListenAndServeTLS("", "")
|
||||||
|
}
|
160
vendor/golang.org/x/crypto/acme/autocert/listener.go
generated
vendored
Normal file
160
vendor/golang.org/x/crypto/acme/autocert/listener.go
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package autocert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewListener returns a net.Listener that listens on the standard TLS
|
||||||
|
// port (443) on all interfaces and returns *tls.Conn connections with
|
||||||
|
// LetsEncrypt certificates for the provided domain or domains.
|
||||||
|
//
|
||||||
|
// It enables one-line HTTPS servers:
|
||||||
|
//
|
||||||
|
// log.Fatal(http.Serve(autocert.NewListener("example.com"), handler))
|
||||||
|
//
|
||||||
|
// NewListener is a convenience function for a common configuration.
|
||||||
|
// More complex or custom configurations can use the autocert.Manager
|
||||||
|
// type instead.
|
||||||
|
//
|
||||||
|
// Use of this function implies acceptance of the LetsEncrypt Terms of
|
||||||
|
// Service. If domains is not empty, the provided domains are passed
|
||||||
|
// to HostWhitelist. If domains is empty, the listener will do
|
||||||
|
// LetsEncrypt challenges for any requested domain, which is not
|
||||||
|
// recommended.
|
||||||
|
//
|
||||||
|
// Certificates are cached in a "golang-autocert" directory under an
|
||||||
|
// operating system-specific cache or temp directory. This may not
|
||||||
|
// be suitable for servers spanning multiple machines.
|
||||||
|
//
|
||||||
|
// The returned listener uses a *tls.Config that enables HTTP/2, and
|
||||||
|
// should only be used with servers that support HTTP/2.
|
||||||
|
//
|
||||||
|
// The returned Listener also enables TCP keep-alives on the accepted
|
||||||
|
// connections. The returned *tls.Conn are returned before their TLS
|
||||||
|
// handshake has completed.
|
||||||
|
func NewListener(domains ...string) net.Listener {
|
||||||
|
m := &Manager{
|
||||||
|
Prompt: AcceptTOS,
|
||||||
|
}
|
||||||
|
if len(domains) > 0 {
|
||||||
|
m.HostPolicy = HostWhitelist(domains...)
|
||||||
|
}
|
||||||
|
dir := cacheDir()
|
||||||
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||||
|
log.Printf("warning: autocert.NewListener not using a cache: %v", err)
|
||||||
|
} else {
|
||||||
|
m.Cache = DirCache(dir)
|
||||||
|
}
|
||||||
|
return m.Listener()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listener listens on the standard TLS port (443) on all interfaces
|
||||||
|
// and returns a net.Listener returning *tls.Conn connections.
|
||||||
|
//
|
||||||
|
// The returned listener uses a *tls.Config that enables HTTP/2, and
|
||||||
|
// should only be used with servers that support HTTP/2.
|
||||||
|
//
|
||||||
|
// The returned Listener also enables TCP keep-alives on the accepted
|
||||||
|
// connections. The returned *tls.Conn are returned before their TLS
|
||||||
|
// handshake has completed.
|
||||||
|
//
|
||||||
|
// Unlike NewListener, it is the caller's responsibility to initialize
|
||||||
|
// 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
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
|
||||||
|
return ln
|
||||||
|
}
|
||||||
|
|
||||||
|
type listener struct {
|
||||||
|
m *Manager
|
||||||
|
conf *tls.Config
|
||||||
|
|
||||||
|
tcpListener net.Listener
|
||||||
|
tcpListenErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ln *listener) Accept() (net.Conn, error) {
|
||||||
|
if ln.tcpListenErr != nil {
|
||||||
|
return nil, ln.tcpListenErr
|
||||||
|
}
|
||||||
|
conn, err := ln.tcpListener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tcpConn := conn.(*net.TCPConn)
|
||||||
|
|
||||||
|
// Because Listener is a convenience function, help out with
|
||||||
|
// this too. This is not possible for the caller to set once
|
||||||
|
// we return a *tcp.Conn wrapping an inaccessible net.Conn.
|
||||||
|
// If callers don't want this, they can do things the manual
|
||||||
|
// way and tweak as needed. But this is what net/http does
|
||||||
|
// itself, so copy that. If net/http changes, we can change
|
||||||
|
// here too.
|
||||||
|
tcpConn.SetKeepAlive(true)
|
||||||
|
tcpConn.SetKeepAlivePeriod(3 * time.Minute)
|
||||||
|
|
||||||
|
return tls.Server(tcpConn, ln.conf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ln *listener) Addr() net.Addr {
|
||||||
|
if ln.tcpListener != nil {
|
||||||
|
return ln.tcpListener.Addr()
|
||||||
|
}
|
||||||
|
// net.Listen failed. Return something non-nil in case callers
|
||||||
|
// call Addr before Accept:
|
||||||
|
return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ln *listener) Close() error {
|
||||||
|
if ln.tcpListenErr != nil {
|
||||||
|
return ln.tcpListenErr
|
||||||
|
}
|
||||||
|
return ln.tcpListener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func homeDir() string {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||||
|
}
|
||||||
|
if h := os.Getenv("HOME"); h != "" {
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
func cacheDir() string {
|
||||||
|
const base = "golang-autocert"
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
return filepath.Join(homeDir(), "Library", "Caches", base)
|
||||||
|
case "windows":
|
||||||
|
for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
|
||||||
|
if v := os.Getenv(ev); v != "" {
|
||||||
|
return filepath.Join(v, base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Worst case:
|
||||||
|
return filepath.Join(homeDir(), base)
|
||||||
|
}
|
||||||
|
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
|
||||||
|
return filepath.Join(xdg, base)
|
||||||
|
}
|
||||||
|
return filepath.Join(homeDir(), ".cache", base)
|
||||||
|
}
|
17
vendor/golang.org/x/crypto/acme/autocert/renewal.go
generated
vendored
17
vendor/golang.org/x/crypto/acme/autocert/renewal.go
generated
vendored
|
@ -5,15 +5,14 @@
|
||||||
package autocert
|
package autocert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto"
|
"crypto"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// maxRandRenew is a maximum deviation from Manager.RenewBefore.
|
// renewJitter is the maximum deviation from Manager.RenewBefore.
|
||||||
const maxRandRenew = time.Hour
|
const renewJitter = time.Hour
|
||||||
|
|
||||||
// domainRenewal tracks the state used by the periodic timers
|
// domainRenewal tracks the state used by the periodic timers
|
||||||
// renewing a single domain's cert.
|
// renewing a single domain's cert.
|
||||||
|
@ -65,7 +64,7 @@ func (dr *domainRenewal) renew() {
|
||||||
// TODO: rotate dr.key at some point?
|
// TODO: rotate dr.key at some point?
|
||||||
next, err := dr.do(ctx)
|
next, err := dr.do(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
next = maxRandRenew / 2
|
next = renewJitter / 2
|
||||||
next += time.Duration(pseudoRand.int63n(int64(next)))
|
next += time.Duration(pseudoRand.int63n(int64(next)))
|
||||||
}
|
}
|
||||||
dr.timer = time.AfterFunc(next, dr.renew)
|
dr.timer = time.AfterFunc(next, dr.renew)
|
||||||
|
@ -83,9 +82,9 @@ func (dr *domainRenewal) renew() {
|
||||||
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
||||||
// a race is likely unavoidable in a distributed environment
|
// a race is likely unavoidable in a distributed environment
|
||||||
// but we try nonetheless
|
// but we try nonetheless
|
||||||
if tlscert, err := dr.m.cacheGet(dr.domain); err == nil {
|
if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil {
|
||||||
next := dr.next(tlscert.Leaf.NotAfter)
|
next := dr.next(tlscert.Leaf.NotAfter)
|
||||||
if next > dr.m.renewBefore()+maxRandRenew {
|
if next > dr.m.renewBefore()+renewJitter {
|
||||||
return next, nil
|
return next, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +102,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
dr.m.cachePut(dr.domain, tlscert)
|
dr.m.cachePut(ctx, dr.domain, tlscert)
|
||||||
dr.m.stateMu.Lock()
|
dr.m.stateMu.Lock()
|
||||||
defer dr.m.stateMu.Unlock()
|
defer dr.m.stateMu.Unlock()
|
||||||
// m.state is guaranteed to be non-nil at this point
|
// m.state is guaranteed to be non-nil at this point
|
||||||
|
@ -114,7 +113,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
||||||
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
|
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
|
||||||
d := expiry.Sub(timeNow()) - dr.m.renewBefore()
|
d := expiry.Sub(timeNow()) - dr.m.renewBefore()
|
||||||
// add a bit of randomness to renew deadline
|
// add a bit of randomness to renew deadline
|
||||||
n := pseudoRand.int63n(int64(maxRandRenew))
|
n := pseudoRand.int63n(int64(renewJitter))
|
||||||
d -= time.Duration(n)
|
d -= time.Duration(n)
|
||||||
if d < 0 {
|
if d < 0 {
|
||||||
return 0
|
return 0
|
||||||
|
|
9
vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
generated
vendored
9
vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
generated
vendored
|
@ -5,6 +5,7 @@
|
||||||
package autocert
|
package autocert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
@ -31,7 +32,7 @@ func TestRenewalNext(t *testing.T) {
|
||||||
expiry time.Time
|
expiry time.Time
|
||||||
min, max time.Duration
|
min, max time.Duration
|
||||||
}{
|
}{
|
||||||
{now.Add(90 * 24 * time.Hour), 83*24*time.Hour - maxRandRenew, 83 * 24 * time.Hour},
|
{now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour},
|
||||||
{now.Add(time.Hour), 0, 1},
|
{now.Add(time.Hour), 0, 1},
|
||||||
{now, 0, 1},
|
{now, 0, 1},
|
||||||
{now.Add(-time.Hour), 0, 1},
|
{now.Add(-time.Hour), 0, 1},
|
||||||
|
@ -111,7 +112,7 @@ func TestRenewFromCache(t *testing.T) {
|
||||||
}
|
}
|
||||||
man := &Manager{
|
man := &Manager{
|
||||||
Prompt: AcceptTOS,
|
Prompt: AcceptTOS,
|
||||||
Cache: make(memCache),
|
Cache: newMemCache(),
|
||||||
RenewBefore: 24 * time.Hour,
|
RenewBefore: 24 * time.Hour,
|
||||||
Client: &acme.Client{
|
Client: &acme.Client{
|
||||||
Key: key,
|
Key: key,
|
||||||
|
@ -127,7 +128,7 @@ func TestRenewFromCache(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
|
tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
|
||||||
if err := man.cachePut(domain, tlscert); err != nil {
|
if err := man.cachePut(context.Background(), domain, tlscert); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ func TestRenewFromCache(t *testing.T) {
|
||||||
|
|
||||||
// ensure the new cert is cached
|
// ensure the new cert is cached
|
||||||
after := time.Now().Add(future)
|
after := time.Now().Add(future)
|
||||||
tlscert, err := man.cacheGet(domain)
|
tlscert, err := man.cacheGet(context.Background(), domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("man.cacheGet: %v", err)
|
t.Fatalf("man.cacheGet: %v", err)
|
||||||
}
|
}
|
||||||
|
|
2
vendor/golang.org/x/crypto/acme/jws.go
generated
vendored
2
vendor/golang.org/x/crypto/acme/jws.go
generated
vendored
|
@ -134,7 +134,7 @@ func jwsHasher(key crypto.Signer) (string, crypto.Hash) {
|
||||||
return "ES256", crypto.SHA256
|
return "ES256", crypto.SHA256
|
||||||
case "P-384":
|
case "P-384":
|
||||||
return "ES384", crypto.SHA384
|
return "ES384", crypto.SHA384
|
||||||
case "P-512":
|
case "P-521":
|
||||||
return "ES512", crypto.SHA512
|
return "ES512", crypto.SHA512
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
185
vendor/golang.org/x/crypto/acme/jws_test.go
generated
vendored
185
vendor/golang.org/x/crypto/acme/jws_test.go
generated
vendored
|
@ -12,11 +12,13 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testKeyPEM = `
|
const (
|
||||||
|
testKeyPEM = `
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
|
MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
|
||||||
WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
|
WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
|
||||||
|
@ -46,10 +48,9 @@ EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
`
|
`
|
||||||
|
|
||||||
// This thumbprint is for the testKey defined above.
|
// This thumbprint is for the testKey defined above.
|
||||||
const testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
|
testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
|
||||||
|
|
||||||
const (
|
|
||||||
// openssl ecparam -name secp256k1 -genkey -noout
|
// openssl ecparam -name secp256k1 -genkey -noout
|
||||||
testKeyECPEM = `
|
testKeyECPEM = `
|
||||||
-----BEGIN EC PRIVATE KEY-----
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
@ -58,39 +59,78 @@ AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5
|
||||||
QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
|
QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
|
||||||
-----END EC PRIVATE KEY-----
|
-----END EC PRIVATE KEY-----
|
||||||
`
|
`
|
||||||
// 1. opnessl ec -in key.pem -noout -text
|
// openssl ecparam -name secp384r1 -genkey -noout
|
||||||
|
testKeyEC384PEM = `
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD
|
||||||
|
Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj
|
||||||
|
JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke
|
||||||
|
WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg=
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
// openssl ecparam -name secp521r1 -genkey -noout
|
||||||
|
testKeyEC512PEM = `
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z
|
||||||
|
KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx
|
||||||
|
7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD
|
||||||
|
FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd
|
||||||
|
GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
|
`
|
||||||
|
// 1. openssl ec -in key.pem -noout -text
|
||||||
// 2. remove first byte, 04 (the header); the rest is X and Y
|
// 2. remove first byte, 04 (the header); the rest is X and Y
|
||||||
// 3. covert each with: echo <val> | xxd -r -p | base64 | tr -d '=' | tr '/+' '_-'
|
// 3. convert each with: echo <val> | xxd -r -p | base64 -w 100 | tr -d '=' | tr '/+' '_-'
|
||||||
testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
|
testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
|
||||||
testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
|
testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
|
||||||
|
testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt"
|
||||||
|
testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo"
|
||||||
|
testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY"
|
||||||
|
testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
|
||||||
|
|
||||||
// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
|
// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
|
||||||
// openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
|
// openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
|
||||||
testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
|
testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testKey *rsa.PrivateKey
|
testKey *rsa.PrivateKey
|
||||||
testKeyEC *ecdsa.PrivateKey
|
testKeyEC *ecdsa.PrivateKey
|
||||||
|
testKeyEC384 *ecdsa.PrivateKey
|
||||||
|
testKeyEC512 *ecdsa.PrivateKey
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
d, _ := pem.Decode([]byte(testKeyPEM))
|
testKey = parseRSA(testKeyPEM, "testKeyPEM")
|
||||||
if d == nil {
|
testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM")
|
||||||
panic("no block found in testKeyPEM")
|
testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM")
|
||||||
}
|
testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM")
|
||||||
var err error
|
}
|
||||||
testKey, err = x509.ParsePKCS1PrivateKey(d.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
panic(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if d, _ = pem.Decode([]byte(testKeyECPEM)); d == nil {
|
func decodePEM(s, name string) []byte {
|
||||||
panic("no block found in testKeyECPEM")
|
d, _ := pem.Decode([]byte(s))
|
||||||
|
if d == nil {
|
||||||
|
panic("no block found in " + name)
|
||||||
}
|
}
|
||||||
testKeyEC, err = x509.ParseECPrivateKey(d.Bytes)
|
return d.Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRSA(s, name string) *rsa.PrivateKey {
|
||||||
|
b := decodePEM(s, name)
|
||||||
|
k, err := x509.ParsePKCS1PrivateKey(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(fmt.Sprintf("%s: %v", name, err))
|
||||||
}
|
}
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEC(s, name string) *ecdsa.PrivateKey {
|
||||||
|
b := decodePEM(s, name)
|
||||||
|
k, err := x509.ParseECPrivateKey(b)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("%s: %v", name, err))
|
||||||
|
}
|
||||||
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJWSEncodeJSON(t *testing.T) {
|
func TestJWSEncodeJSON(t *testing.T) {
|
||||||
|
@ -141,50 +181,63 @@ func TestJWSEncodeJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJWSEncodeJSONEC(t *testing.T) {
|
func TestJWSEncodeJSONEC(t *testing.T) {
|
||||||
claims := struct{ Msg string }{"Hello JWS"}
|
tt := []struct {
|
||||||
|
key *ecdsa.PrivateKey
|
||||||
|
x, y string
|
||||||
|
alg, crv string
|
||||||
|
}{
|
||||||
|
{testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"},
|
||||||
|
{testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"},
|
||||||
|
{testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"},
|
||||||
|
}
|
||||||
|
for i, test := range tt {
|
||||||
|
claims := struct{ Msg string }{"Hello JWS"}
|
||||||
|
b, err := jwsEncodeJSON(claims, test.key, "nonce")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var jws struct{ Protected, Payload, Signature string }
|
||||||
|
if err := json.Unmarshal(b, &jws); err != nil {
|
||||||
|
t.Errorf("%d: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
b, err := jwsEncodeJSON(claims, testKeyEC, "nonce")
|
b, err = base64.RawURLEncoding.DecodeString(jws.Protected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Errorf("%d: jws.Protected: %v", i, err)
|
||||||
}
|
}
|
||||||
var jws struct{ Protected, Payload, Signature string }
|
var head struct {
|
||||||
if err := json.Unmarshal(b, &jws); err != nil {
|
Alg string
|
||||||
t.Fatal(err)
|
Nonce string
|
||||||
}
|
JWK struct {
|
||||||
|
Crv string
|
||||||
if b, err = base64.RawURLEncoding.DecodeString(jws.Protected); err != nil {
|
Kty string
|
||||||
t.Fatalf("jws.Protected: %v", err)
|
X string
|
||||||
}
|
Y string
|
||||||
var head struct {
|
} `json:"jwk"`
|
||||||
Alg string
|
}
|
||||||
Nonce string
|
if err := json.Unmarshal(b, &head); err != nil {
|
||||||
JWK struct {
|
t.Errorf("%d: jws.Protected: %v", i, err)
|
||||||
Crv string
|
}
|
||||||
Kty string
|
if head.Alg != test.alg {
|
||||||
X string
|
t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg)
|
||||||
Y string
|
}
|
||||||
} `json:"jwk"`
|
if head.Nonce != "nonce" {
|
||||||
}
|
t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
|
||||||
if err := json.Unmarshal(b, &head); err != nil {
|
}
|
||||||
t.Fatalf("jws.Protected: %v", err)
|
if head.JWK.Crv != test.crv {
|
||||||
}
|
t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
|
||||||
if head.Alg != "ES256" {
|
}
|
||||||
t.Errorf("head.Alg = %q; want ES256", head.Alg)
|
if head.JWK.Kty != "EC" {
|
||||||
}
|
t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty)
|
||||||
if head.Nonce != "nonce" {
|
}
|
||||||
t.Errorf("head.Nonce = %q; want nonce", head.Nonce)
|
if head.JWK.X != test.x {
|
||||||
}
|
t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x)
|
||||||
if head.JWK.Crv != "P-256" {
|
}
|
||||||
t.Errorf("head.JWK.Crv = %q; want P-256", head.JWK.Crv)
|
if head.JWK.Y != test.y {
|
||||||
}
|
t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y)
|
||||||
if head.JWK.Kty != "EC" {
|
}
|
||||||
t.Errorf("head.JWK.Kty = %q; want EC", head.JWK.Kty)
|
|
||||||
}
|
|
||||||
if head.JWK.X != testKeyECPubX {
|
|
||||||
t.Errorf("head.JWK.X = %q; want %q", head.JWK.X, testKeyECPubX)
|
|
||||||
}
|
|
||||||
if head.JWK.Y != testKeyECPubY {
|
|
||||||
t.Errorf("head.JWK.Y = %q; want %q", head.JWK.Y, testKeyECPubY)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
102
vendor/golang.org/x/crypto/acme/types.go
generated
vendored
102
vendor/golang.org/x/crypto/acme/types.go
generated
vendored
|
@ -1,9 +1,15 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package acme
|
package acme
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ACME server response statuses used to describe Authorization and Challenge states.
|
// ACME server response statuses used to describe Authorization and Challenge states.
|
||||||
|
@ -33,14 +39,8 @@ const (
|
||||||
CRLReasonAACompromise CRLReasonCode = 10
|
CRLReasonAACompromise CRLReasonCode = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
|
||||||
// ErrAuthorizationFailed indicates that an authorization for an identifier
|
var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
|
||||||
// did not succeed.
|
|
||||||
ErrAuthorizationFailed = errors.New("acme: identifier authorization failed")
|
|
||||||
|
|
||||||
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
|
|
||||||
ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Error is an ACME error, defined in Problem Details for HTTP APIs doc
|
// Error is an ACME error, defined in Problem Details for HTTP APIs doc
|
||||||
// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
|
// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
|
||||||
|
@ -53,6 +53,7 @@ type Error struct {
|
||||||
// Detail is a human-readable explanation specific to this occurrence of the problem.
|
// Detail is a human-readable explanation specific to this occurrence of the problem.
|
||||||
Detail string
|
Detail string
|
||||||
// Header is the original server error response headers.
|
// Header is the original server error response headers.
|
||||||
|
// It may be nil.
|
||||||
Header http.Header
|
Header http.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +61,50 @@ func (e *Error) Error() string {
|
||||||
return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
|
return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationError indicates that an authorization for an identifier
|
||||||
|
// did not succeed.
|
||||||
|
// It contains all errors from Challenge items of the failed Authorization.
|
||||||
|
type AuthorizationError struct {
|
||||||
|
// URI uniquely identifies the failed Authorization.
|
||||||
|
URI string
|
||||||
|
|
||||||
|
// Identifier is an AuthzID.Value of the failed Authorization.
|
||||||
|
Identifier string
|
||||||
|
|
||||||
|
// Errors is a collection of non-nil error values of Challenge items
|
||||||
|
// of the failed Authorization.
|
||||||
|
Errors []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AuthorizationError) Error() string {
|
||||||
|
e := make([]string, len(a.Errors))
|
||||||
|
for i, err := range a.Errors {
|
||||||
|
e[i] = err.Error()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RateLimit reports whether err represents a rate limit error and
|
||||||
|
// any Retry-After duration returned by the server.
|
||||||
|
//
|
||||||
|
// See the following for more details on rate limiting:
|
||||||
|
// https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6
|
||||||
|
func RateLimit(err error) (time.Duration, bool) {
|
||||||
|
e, ok := err.(*Error)
|
||||||
|
if !ok {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
// Some CA implementations may return incorrect values.
|
||||||
|
// Use case-insensitive comparison.
|
||||||
|
if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
if e.Header == nil {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
return retryAfter(e.Header.Get("Retry-After"), 0), true
|
||||||
|
}
|
||||||
|
|
||||||
// Account is a user account. It is associated with a private key.
|
// Account is a user account. It is associated with a private key.
|
||||||
type Account struct {
|
type Account struct {
|
||||||
// URI is the account unique ID, which is also a URL used to retrieve
|
// URI is the account unique ID, which is also a URL used to retrieve
|
||||||
|
@ -118,6 +163,8 @@ type Directory struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Challenge encodes a returned CA challenge.
|
// Challenge encodes a returned CA challenge.
|
||||||
|
// Its Error field may be non-nil if the challenge is part of an Authorization
|
||||||
|
// with StatusInvalid.
|
||||||
type Challenge struct {
|
type Challenge struct {
|
||||||
// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
|
// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
|
||||||
Type string
|
Type string
|
||||||
|
@ -130,6 +177,11 @@ type Challenge struct {
|
||||||
|
|
||||||
// Status identifies the status of this challenge.
|
// Status identifies the status of this challenge.
|
||||||
Status string
|
Status string
|
||||||
|
|
||||||
|
// Error indicates the reason for an authorization failure
|
||||||
|
// when this challenge was used.
|
||||||
|
// The type of a non-nil value is *Error.
|
||||||
|
Error error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorization encodes an authorization response.
|
// Authorization encodes an authorization response.
|
||||||
|
@ -187,12 +239,26 @@ func (z *wireAuthz) authorization(uri string) *Authorization {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *wireAuthz) error(uri string) *AuthorizationError {
|
||||||
|
err := &AuthorizationError{
|
||||||
|
URI: uri,
|
||||||
|
Identifier: z.Identifier.Value,
|
||||||
|
}
|
||||||
|
for _, raw := range z.Challenges {
|
||||||
|
if raw.Error != nil {
|
||||||
|
err.Errors = append(err.Errors, raw.Error.error(nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// wireChallenge is ACME JSON challenge representation.
|
// wireChallenge is ACME JSON challenge representation.
|
||||||
type wireChallenge struct {
|
type wireChallenge struct {
|
||||||
URI string `json:"uri"`
|
URI string `json:"uri"`
|
||||||
Type string
|
Type string
|
||||||
Token string
|
Token string
|
||||||
Status string
|
Status string
|
||||||
|
Error *wireError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *wireChallenge) challenge() *Challenge {
|
func (c *wireChallenge) challenge() *Challenge {
|
||||||
|
@ -205,5 +271,25 @@ func (c *wireChallenge) challenge() *Challenge {
|
||||||
if v.Status == "" {
|
if v.Status == "" {
|
||||||
v.Status = StatusPending
|
v.Status = StatusPending
|
||||||
}
|
}
|
||||||
|
if c.Error != nil {
|
||||||
|
v.Error = c.Error.error(nil)
|
||||||
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wireError is a subset of fields of the Problem Details object
|
||||||
|
// as described in https://tools.ietf.org/html/rfc7807#section-3.1.
|
||||||
|
type wireError struct {
|
||||||
|
Status int
|
||||||
|
Type string
|
||||||
|
Detail string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *wireError) error(h http.Header) *Error {
|
||||||
|
return &Error{
|
||||||
|
StatusCode: e.Status,
|
||||||
|
ProblemType: e.Type,
|
||||||
|
Detail: e.Detail,
|
||||||
|
Header: h,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
63
vendor/golang.org/x/crypto/acme/types_test.go
generated
vendored
Normal file
63
vendor/golang.org/x/crypto/acme/types_test.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package acme
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRateLimit(t *testing.T) {
|
||||||
|
now := time.Date(2017, 04, 27, 10, 0, 0, 0, time.UTC)
|
||||||
|
f := timeNow
|
||||||
|
defer func() { timeNow = f }()
|
||||||
|
timeNow = func() time.Time { return now }
|
||||||
|
|
||||||
|
h120, hTime := http.Header{}, http.Header{}
|
||||||
|
h120.Set("Retry-After", "120")
|
||||||
|
hTime.Set("Retry-After", "Tue Apr 27 11:00:00 2017")
|
||||||
|
|
||||||
|
err1 := &Error{
|
||||||
|
ProblemType: "urn:ietf:params:acme:error:nolimit",
|
||||||
|
Header: h120,
|
||||||
|
}
|
||||||
|
err2 := &Error{
|
||||||
|
ProblemType: "urn:ietf:params:acme:error:rateLimited",
|
||||||
|
Header: h120,
|
||||||
|
}
|
||||||
|
err3 := &Error{
|
||||||
|
ProblemType: "urn:ietf:params:acme:error:rateLimited",
|
||||||
|
Header: nil,
|
||||||
|
}
|
||||||
|
err4 := &Error{
|
||||||
|
ProblemType: "urn:ietf:params:acme:error:rateLimited",
|
||||||
|
Header: hTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
err error
|
||||||
|
res time.Duration
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{nil, 0, false},
|
||||||
|
{errors.New("dummy"), 0, false},
|
||||||
|
{err1, 0, false},
|
||||||
|
{err2, 2 * time.Minute, true},
|
||||||
|
{err3, 0, true},
|
||||||
|
{err4, time.Hour, true},
|
||||||
|
}
|
||||||
|
for i, test := range tt {
|
||||||
|
res, ok := RateLimit(test.err)
|
||||||
|
if ok != test.ok {
|
||||||
|
t.Errorf("%d: RateLimit(%+v): ok = %v; want %v", i, test.err, ok, test.ok)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if res != test.res {
|
||||||
|
t.Errorf("%d: RateLimit(%+v) = %v; want %v", i, test.err, res, test.res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
vendor/golang.org/x/crypto/bcrypt/bcrypt.go
generated
vendored
7
vendor/golang.org/x/crypto/bcrypt/bcrypt.go
generated
vendored
|
@ -12,9 +12,10 @@ import (
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/crypto/blowfish"
|
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/blowfish"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -205,7 +206,6 @@ func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
|
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
|
||||||
|
|
||||||
csalt, err := base64Decode(salt)
|
csalt, err := base64Decode(salt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -213,7 +213,8 @@ func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cip
|
||||||
|
|
||||||
// Bug compatibility with C bcrypt implementations. They use the trailing
|
// Bug compatibility with C bcrypt implementations. They use the trailing
|
||||||
// NULL in the key string during expansion.
|
// NULL in the key string during expansion.
|
||||||
ckey := append(key, 0)
|
// We copy the key to prevent changing the underlying array.
|
||||||
|
ckey := append(key[:len(key):len(key)], 0)
|
||||||
|
|
||||||
c, err := blowfish.NewSaltedCipher(ckey, csalt)
|
c, err := blowfish.NewSaltedCipher(ckey, csalt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
17
vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
generated
vendored
17
vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
generated
vendored
|
@ -224,3 +224,20 @@ func BenchmarkGeneration(b *testing.B) {
|
||||||
GenerateFromPassword(passwd, 10)
|
GenerateFromPassword(passwd, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See Issue https://github.com/golang/go/issues/20425.
|
||||||
|
func TestNoSideEffectsFromCompare(t *testing.T) {
|
||||||
|
source := []byte("passw0rd123456")
|
||||||
|
password := source[:len(source)-6]
|
||||||
|
token := source[len(source)-6:]
|
||||||
|
want := make([]byte, len(source))
|
||||||
|
copy(want, source)
|
||||||
|
|
||||||
|
wantHash := []byte("$2a$10$LK9XRuhNxHHCvjX3tdkRKei1QiCDUKrJRhZv7WWZPuQGRUM92rOUa")
|
||||||
|
_ = CompareHashAndPassword(wantHash, password)
|
||||||
|
|
||||||
|
got := bytes.Join([][]byte{password, token}, []byte(""))
|
||||||
|
if !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
vendor/golang.org/x/crypto/blake2b/blake2b.go
generated
vendored
2
vendor/golang.org/x/crypto/blake2b/blake2b.go
generated
vendored
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// Package blake2b implements the BLAKE2b hash algorithm as
|
// Package blake2b implements the BLAKE2b hash algorithm as
|
||||||
// defined in RFC 7693.
|
// defined in RFC 7693.
|
||||||
package blake2b
|
package blake2b // import "golang.org/x/crypto/blake2b"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
688
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
generated
vendored
688
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
generated
vendored
|
@ -54,68 +54,223 @@ DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302
|
||||||
DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
|
DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
|
||||||
GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16
|
GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16
|
||||||
|
|
||||||
// unfortunately the BYTE representation of VPERMQ must be used
|
#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39
|
||||||
#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
|
#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93
|
||||||
VPADDQ m0, Y0, Y0; \
|
#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e
|
||||||
VPADDQ Y1, Y0, Y0; \
|
#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93
|
||||||
VPXOR Y0, Y3, Y3; \
|
#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39
|
||||||
VPSHUFD $-79, Y3, Y3; \
|
|
||||||
VPADDQ Y3, Y2, Y2; \
|
|
||||||
VPXOR Y2, Y1, Y1; \
|
|
||||||
VPSHUFB c40, Y1, Y1; \
|
|
||||||
VPADDQ m1, Y0, Y0; \
|
|
||||||
VPADDQ Y1, Y0, Y0; \
|
|
||||||
VPXOR Y0, Y3, Y3; \
|
|
||||||
VPSHUFB c48, Y3, Y3; \
|
|
||||||
VPADDQ Y3, Y2, Y2; \
|
|
||||||
VPXOR Y2, Y1, Y1; \
|
|
||||||
VPADDQ Y1, Y1, t; \
|
|
||||||
VPSRLQ $63, Y1, Y1; \
|
|
||||||
VPXOR t, Y1, Y1; \
|
|
||||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39 \ // VPERMQ 0x39, Y1, Y1
|
|
||||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e \ // VPERMQ 0x4e, Y2, Y2
|
|
||||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93 \ // VPERMQ 0x93, Y3, Y3
|
|
||||||
VPADDQ m2, Y0, Y0; \
|
|
||||||
VPADDQ Y1, Y0, Y0; \
|
|
||||||
VPXOR Y0, Y3, Y3; \
|
|
||||||
VPSHUFD $-79, Y3, Y3; \
|
|
||||||
VPADDQ Y3, Y2, Y2; \
|
|
||||||
VPXOR Y2, Y1, Y1; \
|
|
||||||
VPSHUFB c40, Y1, Y1; \
|
|
||||||
VPADDQ m3, Y0, Y0; \
|
|
||||||
VPADDQ Y1, Y0, Y0; \
|
|
||||||
VPXOR Y0, Y3, Y3; \
|
|
||||||
VPSHUFB c48, Y3, Y3; \
|
|
||||||
VPADDQ Y3, Y2, Y2; \
|
|
||||||
VPXOR Y2, Y1, Y1; \
|
|
||||||
VPADDQ Y1, Y1, t; \
|
|
||||||
VPSRLQ $63, Y1, Y1; \
|
|
||||||
VPXOR t, Y1, Y1; \
|
|
||||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39 \ // VPERMQ 0x39, Y3, Y3
|
|
||||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e \ // VPERMQ 0x4e, Y2, Y2
|
|
||||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93 \ // VPERMQ 0x93, Y1, Y1
|
|
||||||
|
|
||||||
// load msg into Y12, Y13, Y14, Y15
|
#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
|
||||||
#define LOAD_MSG_AVX2(src, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) \
|
VPADDQ m0, Y0, Y0; \
|
||||||
MOVQ i0*8(src), X12; \
|
VPADDQ Y1, Y0, Y0; \
|
||||||
PINSRQ $1, i1*8(src), X12; \
|
VPXOR Y0, Y3, Y3; \
|
||||||
MOVQ i2*8(src), X11; \
|
VPSHUFD $-79, Y3, Y3; \
|
||||||
PINSRQ $1, i3*8(src), X11; \
|
VPADDQ Y3, Y2, Y2; \
|
||||||
VINSERTI128 $1, X11, Y12, Y12; \
|
VPXOR Y2, Y1, Y1; \
|
||||||
MOVQ i4*8(src), X13; \
|
VPSHUFB c40, Y1, Y1; \
|
||||||
PINSRQ $1, i5*8(src), X13; \
|
VPADDQ m1, Y0, Y0; \
|
||||||
MOVQ i6*8(src), X11; \
|
VPADDQ Y1, Y0, Y0; \
|
||||||
PINSRQ $1, i7*8(src), X11; \
|
VPXOR Y0, Y3, Y3; \
|
||||||
VINSERTI128 $1, X11, Y13, Y13; \
|
VPSHUFB c48, Y3, Y3; \
|
||||||
MOVQ i8*8(src), X14; \
|
VPADDQ Y3, Y2, Y2; \
|
||||||
PINSRQ $1, i9*8(src), X14; \
|
VPXOR Y2, Y1, Y1; \
|
||||||
MOVQ i10*8(src), X11; \
|
VPADDQ Y1, Y1, t; \
|
||||||
PINSRQ $1, i11*8(src), X11; \
|
VPSRLQ $63, Y1, Y1; \
|
||||||
|
VPXOR t, Y1, Y1; \
|
||||||
|
VPERMQ_0x39_Y1_Y1; \
|
||||||
|
VPERMQ_0x4E_Y2_Y2; \
|
||||||
|
VPERMQ_0x93_Y3_Y3; \
|
||||||
|
VPADDQ m2, Y0, Y0; \
|
||||||
|
VPADDQ Y1, Y0, Y0; \
|
||||||
|
VPXOR Y0, Y3, Y3; \
|
||||||
|
VPSHUFD $-79, Y3, Y3; \
|
||||||
|
VPADDQ Y3, Y2, Y2; \
|
||||||
|
VPXOR Y2, Y1, Y1; \
|
||||||
|
VPSHUFB c40, Y1, Y1; \
|
||||||
|
VPADDQ m3, Y0, Y0; \
|
||||||
|
VPADDQ Y1, Y0, Y0; \
|
||||||
|
VPXOR Y0, Y3, Y3; \
|
||||||
|
VPSHUFB c48, Y3, Y3; \
|
||||||
|
VPADDQ Y3, Y2, Y2; \
|
||||||
|
VPXOR Y2, Y1, Y1; \
|
||||||
|
VPADDQ Y1, Y1, t; \
|
||||||
|
VPSRLQ $63, Y1, Y1; \
|
||||||
|
VPXOR t, Y1, Y1; \
|
||||||
|
VPERMQ_0x39_Y3_Y3; \
|
||||||
|
VPERMQ_0x4E_Y2_Y2; \
|
||||||
|
VPERMQ_0x93_Y1_Y1
|
||||||
|
|
||||||
|
#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E
|
||||||
|
#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26
|
||||||
|
#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E
|
||||||
|
#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36
|
||||||
|
#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E
|
||||||
|
|
||||||
|
#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n
|
||||||
|
#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n
|
||||||
|
#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n
|
||||||
|
#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n
|
||||||
|
#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n
|
||||||
|
|
||||||
|
#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01
|
||||||
|
|
||||||
|
#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01
|
||||||
|
#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01
|
||||||
|
|
||||||
|
#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8
|
||||||
|
#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01
|
||||||
|
|
||||||
|
// load msg: Y12 = (i0, i1, i2, i3)
|
||||||
|
// i0, i1, i2, i3 must not be 0
|
||||||
|
#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \
|
||||||
|
VMOVQ_SI_X12(i0*8); \
|
||||||
|
VMOVQ_SI_X11(i2*8); \
|
||||||
|
VPINSRQ_1_SI_X12(i1*8); \
|
||||||
|
VPINSRQ_1_SI_X11(i3*8); \
|
||||||
|
VINSERTI128 $1, X11, Y12, Y12
|
||||||
|
|
||||||
|
// load msg: Y13 = (i0, i1, i2, i3)
|
||||||
|
// i0, i1, i2, i3 must not be 0
|
||||||
|
#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \
|
||||||
|
VMOVQ_SI_X13(i0*8); \
|
||||||
|
VMOVQ_SI_X11(i2*8); \
|
||||||
|
VPINSRQ_1_SI_X13(i1*8); \
|
||||||
|
VPINSRQ_1_SI_X11(i3*8); \
|
||||||
|
VINSERTI128 $1, X11, Y13, Y13
|
||||||
|
|
||||||
|
// load msg: Y14 = (i0, i1, i2, i3)
|
||||||
|
// i0, i1, i2, i3 must not be 0
|
||||||
|
#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \
|
||||||
|
VMOVQ_SI_X14(i0*8); \
|
||||||
|
VMOVQ_SI_X11(i2*8); \
|
||||||
|
VPINSRQ_1_SI_X14(i1*8); \
|
||||||
|
VPINSRQ_1_SI_X11(i3*8); \
|
||||||
|
VINSERTI128 $1, X11, Y14, Y14
|
||||||
|
|
||||||
|
// load msg: Y15 = (i0, i1, i2, i3)
|
||||||
|
// i0, i1, i2, i3 must not be 0
|
||||||
|
#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \
|
||||||
|
VMOVQ_SI_X15(i0*8); \
|
||||||
|
VMOVQ_SI_X11(i2*8); \
|
||||||
|
VPINSRQ_1_SI_X15(i1*8); \
|
||||||
|
VPINSRQ_1_SI_X11(i3*8); \
|
||||||
|
VINSERTI128 $1, X11, Y15, Y15
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \
|
||||||
|
VMOVQ_SI_X12_0; \
|
||||||
|
VMOVQ_SI_X11(4*8); \
|
||||||
|
VPINSRQ_1_SI_X12(2*8); \
|
||||||
|
VPINSRQ_1_SI_X11(6*8); \
|
||||||
|
VINSERTI128 $1, X11, Y12, Y12; \
|
||||||
|
LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \
|
||||||
|
LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \
|
||||||
|
LOAD_MSG_AVX2_Y15(9, 11, 13, 15)
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \
|
||||||
|
LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \
|
||||||
|
LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \
|
||||||
|
VMOVQ_SI_X11(11*8); \
|
||||||
|
VPSHUFD $0x4E, 0*8(SI), X14; \
|
||||||
|
VPINSRQ_1_SI_X11(5*8); \
|
||||||
VINSERTI128 $1, X11, Y14, Y14; \
|
VINSERTI128 $1, X11, Y14, Y14; \
|
||||||
MOVQ i12*8(src), X15; \
|
LOAD_MSG_AVX2_Y15(12, 2, 7, 3)
|
||||||
PINSRQ $1, i13*8(src), X15; \
|
|
||||||
MOVQ i14*8(src), X11; \
|
#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \
|
||||||
PINSRQ $1, i15*8(src), X11; \
|
VMOVQ_SI_X11(5*8); \
|
||||||
|
VMOVDQU 11*8(SI), X12; \
|
||||||
|
VPINSRQ_1_SI_X11(15*8); \
|
||||||
|
VINSERTI128 $1, X11, Y12, Y12; \
|
||||||
|
VMOVQ_SI_X13(8*8); \
|
||||||
|
VMOVQ_SI_X11(2*8); \
|
||||||
|
VPINSRQ_1_SI_X13_0; \
|
||||||
|
VPINSRQ_1_SI_X11(13*8); \
|
||||||
|
VINSERTI128 $1, X11, Y13, Y13; \
|
||||||
|
LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \
|
||||||
|
LOAD_MSG_AVX2_Y15(14, 6, 1, 4)
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \
|
||||||
|
LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \
|
||||||
|
LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \
|
||||||
|
LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \
|
||||||
|
VMOVQ_SI_X15(6*8); \
|
||||||
|
VMOVQ_SI_X11_0; \
|
||||||
|
VPINSRQ_1_SI_X15(10*8); \
|
||||||
|
VPINSRQ_1_SI_X11(8*8); \
|
||||||
|
VINSERTI128 $1, X11, Y15, Y15
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \
|
||||||
|
LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \
|
||||||
|
VMOVQ_SI_X13_0; \
|
||||||
|
VMOVQ_SI_X11(4*8); \
|
||||||
|
VPINSRQ_1_SI_X13(7*8); \
|
||||||
|
VPINSRQ_1_SI_X11(15*8); \
|
||||||
|
VINSERTI128 $1, X11, Y13, Y13; \
|
||||||
|
LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \
|
||||||
|
LOAD_MSG_AVX2_Y15(1, 12, 8, 13)
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \
|
||||||
|
VMOVQ_SI_X12(2*8); \
|
||||||
|
VMOVQ_SI_X11_0; \
|
||||||
|
VPINSRQ_1_SI_X12(6*8); \
|
||||||
|
VPINSRQ_1_SI_X11(8*8); \
|
||||||
|
VINSERTI128 $1, X11, Y12, Y12; \
|
||||||
|
LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \
|
||||||
|
LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \
|
||||||
|
LOAD_MSG_AVX2_Y15(13, 5, 14, 9)
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \
|
||||||
|
LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \
|
||||||
|
LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \
|
||||||
|
VMOVQ_SI_X14_0; \
|
||||||
|
VPSHUFD $0x4E, 8*8(SI), X11; \
|
||||||
|
VPINSRQ_1_SI_X14(6*8); \
|
||||||
|
VINSERTI128 $1, X11, Y14, Y14; \
|
||||||
|
LOAD_MSG_AVX2_Y15(7, 3, 2, 11)
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \
|
||||||
|
LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \
|
||||||
|
LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \
|
||||||
|
LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \
|
||||||
|
VMOVQ_SI_X15_0; \
|
||||||
|
VMOVQ_SI_X11(6*8); \
|
||||||
|
VPINSRQ_1_SI_X15(4*8); \
|
||||||
|
VPINSRQ_1_SI_X11(10*8); \
|
||||||
|
VINSERTI128 $1, X11, Y15, Y15
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \
|
||||||
|
VMOVQ_SI_X12(6*8); \
|
||||||
|
VMOVQ_SI_X11(11*8); \
|
||||||
|
VPINSRQ_1_SI_X12(14*8); \
|
||||||
|
VPINSRQ_1_SI_X11_0; \
|
||||||
|
VINSERTI128 $1, X11, Y12, Y12; \
|
||||||
|
LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \
|
||||||
|
VMOVQ_SI_X11(1*8); \
|
||||||
|
VMOVDQU 12*8(SI), X14; \
|
||||||
|
VPINSRQ_1_SI_X11(10*8); \
|
||||||
|
VINSERTI128 $1, X11, Y14, Y14; \
|
||||||
|
VMOVQ_SI_X15(2*8); \
|
||||||
|
VMOVDQU 4*8(SI), X11; \
|
||||||
|
VPINSRQ_1_SI_X15(7*8); \
|
||||||
|
VINSERTI128 $1, X11, Y15, Y15
|
||||||
|
|
||||||
|
#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \
|
||||||
|
LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \
|
||||||
|
VMOVQ_SI_X13(2*8); \
|
||||||
|
VPSHUFD $0x4E, 5*8(SI), X11; \
|
||||||
|
VPINSRQ_1_SI_X13(4*8); \
|
||||||
|
VINSERTI128 $1, X11, Y13, Y13; \
|
||||||
|
LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \
|
||||||
|
VMOVQ_SI_X15(11*8); \
|
||||||
|
VMOVQ_SI_X11(12*8); \
|
||||||
|
VPINSRQ_1_SI_X15(14*8); \
|
||||||
|
VPINSRQ_1_SI_X11_0; \
|
||||||
VINSERTI128 $1, X11, Y15, Y15
|
VINSERTI128 $1, X11, Y15, Y15
|
||||||
|
|
||||||
// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||||
|
@ -162,34 +317,34 @@ noinc:
|
||||||
VMOVDQA Y6, Y2
|
VMOVDQA Y6, Y2
|
||||||
VPXOR 0(SP), Y7, Y3
|
VPXOR 0(SP), Y7, Y3
|
||||||
|
|
||||||
LOAD_MSG_AVX2(SI, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15)
|
LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15()
|
||||||
VMOVDQA Y12, 32(SP)
|
VMOVDQA Y12, 32(SP)
|
||||||
VMOVDQA Y13, 64(SP)
|
VMOVDQA Y13, 64(SP)
|
||||||
VMOVDQA Y14, 96(SP)
|
VMOVDQA Y14, 96(SP)
|
||||||
VMOVDQA Y15, 128(SP)
|
VMOVDQA Y15, 128(SP)
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3)
|
LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3()
|
||||||
VMOVDQA Y12, 160(SP)
|
VMOVDQA Y12, 160(SP)
|
||||||
VMOVDQA Y13, 192(SP)
|
VMOVDQA Y13, 192(SP)
|
||||||
VMOVDQA Y14, 224(SP)
|
VMOVDQA Y14, 224(SP)
|
||||||
VMOVDQA Y15, 256(SP)
|
VMOVDQA Y15, 256(SP)
|
||||||
|
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4)
|
LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8)
|
LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13)
|
LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9)
|
LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11)
|
LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10)
|
LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5)
|
LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
LOAD_MSG_AVX2(SI, 10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0)
|
LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0()
|
||||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||||
|
|
||||||
ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5)
|
ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5)
|
||||||
|
@ -209,56 +364,55 @@ noinc:
|
||||||
|
|
||||||
VMOVDQU Y8, 0(AX)
|
VMOVDQU Y8, 0(AX)
|
||||||
VMOVDQU Y9, 32(AX)
|
VMOVDQU Y9, 32(AX)
|
||||||
|
VZEROUPPER
|
||||||
|
|
||||||
MOVQ DX, SP
|
MOVQ DX, SP
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// unfortunately the BYTE representation of VPUNPCKLQDQ and VPUNPCKHQDQ must be used
|
#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA
|
||||||
#define VPUNPCKLQDQ_X8_X8_X10 BYTE $0xC4; BYTE $0x41; BYTE $0x39; BYTE $0x6C; BYTE $0xD0
|
#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB
|
||||||
#define VPUNPCKHQDQ_X7_X10_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF2
|
#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF
|
||||||
#define VPUNPCKLQDQ_X7_X7_X10 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xD7
|
#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD
|
||||||
#define VPUNPCKHQDQ_X8_X10_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x39; BYTE $0x6D; BYTE $0xFA
|
#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE
|
||||||
#define VPUNPCKLQDQ_X3_X3_X10 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xD3
|
|
||||||
#define VPUNPCKHQDQ_X2_X10_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD2
|
#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7
|
||||||
#define VPUNPCKLQDQ_X9_X9_X10 BYTE $0xC4; BYTE $0x41; BYTE $0x31; BYTE $0x6C; BYTE $0xD1
|
#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF
|
||||||
#define VPUNPCKHQDQ_X3_X10_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDA
|
#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7
|
||||||
#define VPUNPCKLQDQ_X2_X2_X10 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xD2
|
#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF
|
||||||
#define VPUNPCKHQDQ_X3_X10_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD2
|
#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7
|
||||||
#define VPUNPCKHQDQ_X8_X10_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x39; BYTE $0x6D; BYTE $0xDA
|
#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7
|
||||||
#define VPUNPCKHQDQ_X6_X10_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF2
|
#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF
|
||||||
#define VPUNPCKHQDQ_X7_X10_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFA
|
#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF
|
||||||
|
|
||||||
// shuffle X2 and X6 using the temp registers X8, X9, X10
|
|
||||||
#define SHUFFLE_AVX() \
|
#define SHUFFLE_AVX() \
|
||||||
VMOVDQA X4, X9; \
|
VMOVDQA X6, X13; \
|
||||||
VMOVDQA X5, X4; \
|
VMOVDQA X2, X14; \
|
||||||
VMOVDQA X9, X5; \
|
VMOVDQA X4, X6; \
|
||||||
VMOVDQA X6, X8; \
|
VPUNPCKLQDQ_X13_X13_X15; \
|
||||||
VPUNPCKLQDQ_X8_X8_X10; \
|
VMOVDQA X5, X4; \
|
||||||
VPUNPCKHQDQ_X7_X10_X6; \
|
VMOVDQA X6, X5; \
|
||||||
VPUNPCKLQDQ_X7_X7_X10; \
|
VPUNPCKHQDQ_X15_X7_X6; \
|
||||||
VPUNPCKHQDQ_X8_X10_X7; \
|
VPUNPCKLQDQ_X7_X7_X15; \
|
||||||
VPUNPCKLQDQ_X3_X3_X10; \
|
VPUNPCKHQDQ_X15_X13_X7; \
|
||||||
VMOVDQA X2, X9; \
|
VPUNPCKLQDQ_X3_X3_X15; \
|
||||||
VPUNPCKHQDQ_X2_X10_X2; \
|
VPUNPCKHQDQ_X15_X2_X2; \
|
||||||
VPUNPCKLQDQ_X9_X9_X10; \
|
VPUNPCKLQDQ_X14_X14_X15; \
|
||||||
VPUNPCKHQDQ_X3_X10_X3; \
|
VPUNPCKHQDQ_X15_X3_X3; \
|
||||||
|
|
||||||
// inverse shuffle X2 and X6 using the temp registers X8, X9, X10
|
|
||||||
#define SHUFFLE_AVX_INV() \
|
#define SHUFFLE_AVX_INV() \
|
||||||
VMOVDQA X4, X9; \
|
VMOVDQA X2, X13; \
|
||||||
VMOVDQA X5, X4; \
|
VMOVDQA X4, X14; \
|
||||||
VMOVDQA X9, X5; \
|
VPUNPCKLQDQ_X2_X2_X15; \
|
||||||
VMOVDQA X2, X8; \
|
VMOVDQA X5, X4; \
|
||||||
VPUNPCKLQDQ_X2_X2_X10; \
|
VPUNPCKHQDQ_X15_X3_X2; \
|
||||||
VPUNPCKHQDQ_X3_X10_X2; \
|
VMOVDQA X14, X5; \
|
||||||
VPUNPCKLQDQ_X3_X3_X10; \
|
VPUNPCKLQDQ_X3_X3_X15; \
|
||||||
VPUNPCKHQDQ_X8_X10_X3; \
|
VMOVDQA X6, X14; \
|
||||||
VPUNPCKLQDQ_X7_X7_X10; \
|
VPUNPCKHQDQ_X15_X13_X3; \
|
||||||
VMOVDQA X6, X9; \
|
VPUNPCKLQDQ_X7_X7_X15; \
|
||||||
VPUNPCKHQDQ_X6_X10_X6; \
|
VPUNPCKHQDQ_X15_X6_X6; \
|
||||||
VPUNPCKLQDQ_X9_X9_X10; \
|
VPUNPCKLQDQ_X14_X14_X15; \
|
||||||
VPUNPCKHQDQ_X7_X10_X7; \
|
VPUNPCKHQDQ_X15_X7_X7; \
|
||||||
|
|
||||||
#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
|
#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
|
||||||
VPADDQ m0, v0, v0; \
|
VPADDQ m0, v0, v0; \
|
||||||
|
@ -294,28 +448,133 @@ noinc:
|
||||||
VPSRLQ $63, v3, v3; \
|
VPSRLQ $63, v3, v3; \
|
||||||
VPXOR t0, v3, v3
|
VPXOR t0, v3, v3
|
||||||
|
|
||||||
// unfortunately the BYTE representation of VPINSRQ must be used
|
// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7)
|
||||||
#define VPINSRQ_1_R10_X8_X8 BYTE $0xC4; BYTE $0x43; BYTE $0xB9; BYTE $0x22; BYTE $0xC2; BYTE $0x01
|
// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0
|
||||||
#define VPINSRQ_1_R11_X9_X9 BYTE $0xC4; BYTE $0x43; BYTE $0xB1; BYTE $0x22; BYTE $0xCB; BYTE $0x01
|
#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \
|
||||||
#define VPINSRQ_1_R12_X10_X10 BYTE $0xC4; BYTE $0x43; BYTE $0xA9; BYTE $0x22; BYTE $0xD4; BYTE $0x01
|
VMOVQ_SI_X12(i0*8); \
|
||||||
#define VPINSRQ_1_R13_X11_X11 BYTE $0xC4; BYTE $0x43; BYTE $0xA1; BYTE $0x22; BYTE $0xDD; BYTE $0x01
|
VMOVQ_SI_X13(i2*8); \
|
||||||
|
VMOVQ_SI_X14(i4*8); \
|
||||||
|
VMOVQ_SI_X15(i6*8); \
|
||||||
|
VPINSRQ_1_SI_X12(i1*8); \
|
||||||
|
VPINSRQ_1_SI_X13(i3*8); \
|
||||||
|
VPINSRQ_1_SI_X14(i5*8); \
|
||||||
|
VPINSRQ_1_SI_X15(i7*8)
|
||||||
|
|
||||||
#define VPINSRQ_1_R9_X8_X8 BYTE $0xC4; BYTE $0x43; BYTE $0xB9; BYTE $0x22; BYTE $0xC1; BYTE $0x01
|
// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7)
|
||||||
|
#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \
|
||||||
|
VMOVQ_SI_X12_0; \
|
||||||
|
VMOVQ_SI_X13(4*8); \
|
||||||
|
VMOVQ_SI_X14(1*8); \
|
||||||
|
VMOVQ_SI_X15(5*8); \
|
||||||
|
VPINSRQ_1_SI_X12(2*8); \
|
||||||
|
VPINSRQ_1_SI_X13(6*8); \
|
||||||
|
VPINSRQ_1_SI_X14(3*8); \
|
||||||
|
VPINSRQ_1_SI_X15(7*8)
|
||||||
|
|
||||||
// load src into X8, X9, X10 and X11 using R10, R11, R12 and R13 for temp registers
|
// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3)
|
||||||
#define LOAD_MSG_AVX(src, i0, i1, i2, i3, i4, i5, i6, i7) \
|
#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \
|
||||||
MOVQ i0*8(src), X8; \
|
VPSHUFD $0x4E, 0*8(SI), X12; \
|
||||||
MOVQ i1*8(src), R10; \
|
VMOVQ_SI_X13(11*8); \
|
||||||
MOVQ i2*8(src), X9; \
|
VMOVQ_SI_X14(12*8); \
|
||||||
MOVQ i3*8(src), R11; \
|
VMOVQ_SI_X15(7*8); \
|
||||||
MOVQ i4*8(src), X10; \
|
VPINSRQ_1_SI_X13(5*8); \
|
||||||
MOVQ i5*8(src), R12; \
|
VPINSRQ_1_SI_X14(2*8); \
|
||||||
MOVQ i6*8(src), X11; \
|
VPINSRQ_1_SI_X15(3*8)
|
||||||
MOVQ i7*8(src), R13; \
|
|
||||||
VPINSRQ_1_R10_X8_X8; \
|
// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13)
|
||||||
VPINSRQ_1_R11_X9_X9; \
|
#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \
|
||||||
VPINSRQ_1_R12_X10_X10; \
|
VMOVDQU 11*8(SI), X12; \
|
||||||
VPINSRQ_1_R13_X11_X11
|
VMOVQ_SI_X13(5*8); \
|
||||||
|
VMOVQ_SI_X14(8*8); \
|
||||||
|
VMOVQ_SI_X15(2*8); \
|
||||||
|
VPINSRQ_1_SI_X13(15*8); \
|
||||||
|
VPINSRQ_1_SI_X14_0; \
|
||||||
|
VPINSRQ_1_SI_X15(13*8)
|
||||||
|
|
||||||
|
// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8)
|
||||||
|
#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \
|
||||||
|
VMOVQ_SI_X12(2*8); \
|
||||||
|
VMOVQ_SI_X13(4*8); \
|
||||||
|
VMOVQ_SI_X14(6*8); \
|
||||||
|
VMOVQ_SI_X15_0; \
|
||||||
|
VPINSRQ_1_SI_X12(5*8); \
|
||||||
|
VPINSRQ_1_SI_X13(15*8); \
|
||||||
|
VPINSRQ_1_SI_X14(10*8); \
|
||||||
|
VPINSRQ_1_SI_X15(8*8)
|
||||||
|
|
||||||
|
// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15)
|
||||||
|
#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \
|
||||||
|
VMOVQ_SI_X12(9*8); \
|
||||||
|
VMOVQ_SI_X13(2*8); \
|
||||||
|
VMOVQ_SI_X14_0; \
|
||||||
|
VMOVQ_SI_X15(4*8); \
|
||||||
|
VPINSRQ_1_SI_X12(5*8); \
|
||||||
|
VPINSRQ_1_SI_X13(10*8); \
|
||||||
|
VPINSRQ_1_SI_X14(7*8); \
|
||||||
|
VPINSRQ_1_SI_X15(15*8)
|
||||||
|
|
||||||
|
// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3)
|
||||||
|
#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \
|
||||||
|
VMOVQ_SI_X12(2*8); \
|
||||||
|
VMOVQ_SI_X13_0; \
|
||||||
|
VMOVQ_SI_X14(12*8); \
|
||||||
|
VMOVQ_SI_X15(11*8); \
|
||||||
|
VPINSRQ_1_SI_X12(6*8); \
|
||||||
|
VPINSRQ_1_SI_X13(8*8); \
|
||||||
|
VPINSRQ_1_SI_X14(10*8); \
|
||||||
|
VPINSRQ_1_SI_X15(3*8)
|
||||||
|
|
||||||
|
// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11)
|
||||||
|
#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \
|
||||||
|
MOVQ 0*8(SI), X12; \
|
||||||
|
VPSHUFD $0x4E, 8*8(SI), X13; \
|
||||||
|
MOVQ 7*8(SI), X14; \
|
||||||
|
MOVQ 2*8(SI), X15; \
|
||||||
|
VPINSRQ_1_SI_X12(6*8); \
|
||||||
|
VPINSRQ_1_SI_X14(3*8); \
|
||||||
|
VPINSRQ_1_SI_X15(11*8)
|
||||||
|
|
||||||
|
// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8)
|
||||||
|
#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \
|
||||||
|
MOVQ 6*8(SI), X12; \
|
||||||
|
MOVQ 11*8(SI), X13; \
|
||||||
|
MOVQ 15*8(SI), X14; \
|
||||||
|
MOVQ 3*8(SI), X15; \
|
||||||
|
VPINSRQ_1_SI_X12(14*8); \
|
||||||
|
VPINSRQ_1_SI_X13_0; \
|
||||||
|
VPINSRQ_1_SI_X14(9*8); \
|
||||||
|
VPINSRQ_1_SI_X15(8*8)
|
||||||
|
|
||||||
|
// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10)
|
||||||
|
#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \
|
||||||
|
MOVQ 5*8(SI), X12; \
|
||||||
|
MOVQ 8*8(SI), X13; \
|
||||||
|
MOVQ 0*8(SI), X14; \
|
||||||
|
MOVQ 6*8(SI), X15; \
|
||||||
|
VPINSRQ_1_SI_X12(15*8); \
|
||||||
|
VPINSRQ_1_SI_X13(2*8); \
|
||||||
|
VPINSRQ_1_SI_X14(4*8); \
|
||||||
|
VPINSRQ_1_SI_X15(10*8)
|
||||||
|
|
||||||
|
// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5)
|
||||||
|
#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \
|
||||||
|
VMOVDQU 12*8(SI), X12; \
|
||||||
|
MOVQ 1*8(SI), X13; \
|
||||||
|
MOVQ 2*8(SI), X14; \
|
||||||
|
VPINSRQ_1_SI_X13(10*8); \
|
||||||
|
VPINSRQ_1_SI_X14(7*8); \
|
||||||
|
VMOVDQU 4*8(SI), X15
|
||||||
|
|
||||||
|
// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0)
|
||||||
|
#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \
|
||||||
|
MOVQ 15*8(SI), X12; \
|
||||||
|
MOVQ 3*8(SI), X13; \
|
||||||
|
MOVQ 11*8(SI), X14; \
|
||||||
|
MOVQ 12*8(SI), X15; \
|
||||||
|
VPINSRQ_1_SI_X12(9*8); \
|
||||||
|
VPINSRQ_1_SI_X13(13*8); \
|
||||||
|
VPINSRQ_1_SI_X14(14*8); \
|
||||||
|
VPINSRQ_1_SI_X15_0
|
||||||
|
|
||||||
// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||||
TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
|
TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
|
||||||
|
@ -331,15 +590,17 @@ TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
|
||||||
ANDQ $~15, R9
|
ANDQ $~15, R9
|
||||||
MOVQ R9, SP
|
MOVQ R9, SP
|
||||||
|
|
||||||
MOVOU ·AVX_c40<>(SB), X13
|
VMOVDQU ·AVX_c40<>(SB), X0
|
||||||
MOVOU ·AVX_c48<>(SB), X14
|
VMOVDQU ·AVX_c48<>(SB), X1
|
||||||
|
VMOVDQA X0, X8
|
||||||
|
VMOVDQA X1, X9
|
||||||
|
|
||||||
VMOVDQU ·AVX_iv3<>(SB), X0
|
VMOVDQU ·AVX_iv3<>(SB), X0
|
||||||
VMOVDQA X0, 0(SP)
|
VMOVDQA X0, 0(SP)
|
||||||
XORQ CX, 0(SP) // 0(SP) = ·AVX_iv3 ^ (CX || 0)
|
XORQ CX, 0(SP) // 0(SP) = ·AVX_iv3 ^ (CX || 0)
|
||||||
|
|
||||||
VMOVDQU 0(AX), X12
|
VMOVDQU 0(AX), X10
|
||||||
VMOVDQU 16(AX), X15
|
VMOVDQU 16(AX), X11
|
||||||
VMOVDQU 32(AX), X2
|
VMOVDQU 32(AX), X2
|
||||||
VMOVDQU 48(AX), X3
|
VMOVDQU 48(AX), X3
|
||||||
|
|
||||||
|
@ -353,124 +614,124 @@ loop:
|
||||||
INCQ R9
|
INCQ R9
|
||||||
|
|
||||||
noinc:
|
noinc:
|
||||||
MOVQ R8, X8
|
VMOVQ_R8_X15
|
||||||
VPINSRQ_1_R9_X8_X8
|
VPINSRQ_1_R9_X15
|
||||||
|
|
||||||
VMOVDQA X12, X0
|
VMOVDQA X10, X0
|
||||||
VMOVDQA X15, X1
|
VMOVDQA X11, X1
|
||||||
VMOVDQU ·AVX_iv0<>(SB), X4
|
VMOVDQU ·AVX_iv0<>(SB), X4
|
||||||
VMOVDQU ·AVX_iv1<>(SB), X5
|
VMOVDQU ·AVX_iv1<>(SB), X5
|
||||||
VMOVDQU ·AVX_iv2<>(SB), X6
|
VMOVDQU ·AVX_iv2<>(SB), X6
|
||||||
|
|
||||||
VPXOR X8, X6, X6
|
VPXOR X15, X6, X6
|
||||||
VMOVDQA 0(SP), X7
|
VMOVDQA 0(SP), X7
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 0, 2, 4, 6, 1, 3, 5, 7)
|
LOAD_MSG_AVX_0_2_4_6_1_3_5_7()
|
||||||
VMOVDQA X8, 16(SP)
|
VMOVDQA X12, 16(SP)
|
||||||
VMOVDQA X9, 32(SP)
|
VMOVDQA X13, 32(SP)
|
||||||
VMOVDQA X10, 48(SP)
|
VMOVDQA X14, 48(SP)
|
||||||
VMOVDQA X11, 64(SP)
|
VMOVDQA X15, 64(SP)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 8, 10, 12, 14, 9, 11, 13, 15)
|
LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15)
|
||||||
VMOVDQA X8, 80(SP)
|
VMOVDQA X12, 80(SP)
|
||||||
VMOVDQA X9, 96(SP)
|
VMOVDQA X13, 96(SP)
|
||||||
VMOVDQA X10, 112(SP)
|
VMOVDQA X14, 112(SP)
|
||||||
VMOVDQA X11, 128(SP)
|
VMOVDQA X15, 128(SP)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 14, 4, 9, 13, 10, 8, 15, 6)
|
LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6)
|
||||||
VMOVDQA X8, 144(SP)
|
VMOVDQA X12, 144(SP)
|
||||||
VMOVDQA X9, 160(SP)
|
VMOVDQA X13, 160(SP)
|
||||||
VMOVDQA X10, 176(SP)
|
VMOVDQA X14, 176(SP)
|
||||||
VMOVDQA X11, 192(SP)
|
VMOVDQA X15, 192(SP)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 1, 0, 11, 5, 12, 2, 7, 3)
|
LOAD_MSG_AVX_1_0_11_5_12_2_7_3()
|
||||||
VMOVDQA X8, 208(SP)
|
VMOVDQA X12, 208(SP)
|
||||||
VMOVDQA X9, 224(SP)
|
VMOVDQA X13, 224(SP)
|
||||||
VMOVDQA X10, 240(SP)
|
VMOVDQA X14, 240(SP)
|
||||||
VMOVDQA X11, 256(SP)
|
VMOVDQA X15, 256(SP)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 11, 12, 5, 15, 8, 0, 2, 13)
|
LOAD_MSG_AVX_11_12_5_15_8_0_2_13()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 10, 3, 7, 9, 14, 6, 1, 4)
|
LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 7, 3, 13, 11, 9, 1, 12, 14)
|
LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 2, 5, 4, 15, 6, 10, 0, 8)
|
LOAD_MSG_AVX_2_5_4_15_6_10_0_8()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 9, 5, 2, 10, 0, 7, 4, 15)
|
LOAD_MSG_AVX_9_5_2_10_0_7_4_15()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 14, 11, 6, 3, 1, 12, 8, 13)
|
LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 2, 6, 0, 8, 12, 10, 11, 3)
|
LOAD_MSG_AVX_2_6_0_8_12_10_11_3()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 4, 7, 15, 1, 13, 5, 14, 9)
|
LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 12, 1, 14, 4, 5, 15, 13, 10)
|
LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 0, 6, 9, 8, 7, 3, 2, 11)
|
LOAD_MSG_AVX_0_6_9_8_7_3_2_11()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 13, 7, 12, 3, 11, 14, 1, 9)
|
LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 5, 15, 8, 2, 0, 4, 6, 10)
|
LOAD_MSG_AVX_5_15_8_2_0_4_6_10()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 6, 14, 11, 0, 15, 9, 3, 8)
|
LOAD_MSG_AVX_6_14_11_0_15_9_3_8()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 12, 13, 1, 10, 2, 7, 4, 5)
|
LOAD_MSG_AVX_12_13_1_10_2_7_4_5()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
LOAD_MSG_AVX(SI, 10, 8, 7, 1, 2, 4, 6, 5)
|
LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5)
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
LOAD_MSG_AVX(SI, 15, 9, 3, 13, 11, 14, 12, 0)
|
LOAD_MSG_AVX_15_9_3_13_11_14_12_0()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X15, X8, X9)
|
||||||
SHUFFLE_AVX()
|
SHUFFLE_AVX()
|
||||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X11, X13, X14)
|
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X15, X8, X9)
|
||||||
SHUFFLE_AVX_INV()
|
SHUFFLE_AVX_INV()
|
||||||
|
|
||||||
VMOVDQU 32(AX), X10
|
VMOVDQU 32(AX), X14
|
||||||
VMOVDQU 48(AX), X11
|
VMOVDQU 48(AX), X15
|
||||||
VPXOR X0, X12, X12
|
VPXOR X0, X10, X10
|
||||||
VPXOR X1, X15, X15
|
VPXOR X1, X11, X11
|
||||||
VPXOR X2, X10, X10
|
VPXOR X2, X14, X14
|
||||||
VPXOR X3, X11, X11
|
VPXOR X3, X15, X15
|
||||||
VPXOR X4, X12, X12
|
VPXOR X4, X10, X10
|
||||||
VPXOR X5, X15, X15
|
VPXOR X5, X11, X11
|
||||||
VPXOR X6, X10, X2
|
VPXOR X6, X14, X2
|
||||||
VPXOR X7, X11, X3
|
VPXOR X7, X15, X3
|
||||||
VMOVDQU X2, 32(AX)
|
VMOVDQU X2, 32(AX)
|
||||||
VMOVDQU X3, 48(AX)
|
VMOVDQU X3, 48(AX)
|
||||||
|
|
||||||
|
@ -478,12 +739,11 @@ noinc:
|
||||||
SUBQ $128, DI
|
SUBQ $128, DI
|
||||||
JNE loop
|
JNE loop
|
||||||
|
|
||||||
VMOVDQU X12, 0(AX)
|
VMOVDQU X10, 0(AX)
|
||||||
VMOVDQU X15, 16(AX)
|
VMOVDQU X11, 16(AX)
|
||||||
|
|
||||||
MOVQ R8, 0(BX)
|
MOVQ R8, 0(BX)
|
||||||
MOVQ R9, 8(BX)
|
MOVQ R9, 8(BX)
|
||||||
|
|
||||||
VZEROUPPER
|
VZEROUPPER
|
||||||
|
|
||||||
MOVQ BP, SP
|
MOVQ BP, SP
|
||||||
|
|
2
vendor/golang.org/x/crypto/blake2b/blake2b_test.go
generated
vendored
2
vendor/golang.org/x/crypto/blake2b/blake2b_test.go
generated
vendored
|
@ -22,7 +22,7 @@ func fromHex(s string) []byte {
|
||||||
|
|
||||||
func TestHashes(t *testing.T) {
|
func TestHashes(t *testing.T) {
|
||||||
defer func(sse4, avx, avx2 bool) {
|
defer func(sse4, avx, avx2 bool) {
|
||||||
useSSE4, useAVX, useAVX2 = sse4, useAVX, avx2
|
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
|
||||||
}(useSSE4, useAVX, useAVX2)
|
}(useSSE4, useAVX, useAVX2)
|
||||||
|
|
||||||
if useAVX2 {
|
if useAVX2 {
|
||||||
|
|
32
vendor/golang.org/x/crypto/blake2b/register.go
generated
vendored
Normal file
32
vendor/golang.org/x/crypto/blake2b/register.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package blake2b
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
newHash256 := func() hash.Hash {
|
||||||
|
h, _ := New256(nil)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
newHash384 := func() hash.Hash {
|
||||||
|
h, _ := New384(nil)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
newHash512 := func() hash.Hash {
|
||||||
|
h, _ := New512(nil)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto.RegisterHash(crypto.BLAKE2b_256, newHash256)
|
||||||
|
crypto.RegisterHash(crypto.BLAKE2b_384, newHash384)
|
||||||
|
crypto.RegisterHash(crypto.BLAKE2b_512, newHash512)
|
||||||
|
}
|
17
vendor/golang.org/x/crypto/blake2s/blake2s.go
generated
vendored
17
vendor/golang.org/x/crypto/blake2s/blake2s.go
generated
vendored
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// Package blake2s implements the BLAKE2s hash algorithm as
|
// Package blake2s implements the BLAKE2s hash algorithm as
|
||||||
// defined in RFC 7693.
|
// defined in RFC 7693.
|
||||||
package blake2s
|
package blake2s // import "golang.org/x/crypto/blake2s"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
@ -15,8 +15,12 @@ import (
|
||||||
const (
|
const (
|
||||||
// The blocksize of BLAKE2s in bytes.
|
// The blocksize of BLAKE2s in bytes.
|
||||||
BlockSize = 64
|
BlockSize = 64
|
||||||
|
|
||||||
// The hash size of BLAKE2s-256 in bytes.
|
// The hash size of BLAKE2s-256 in bytes.
|
||||||
Size = 32
|
Size = 32
|
||||||
|
|
||||||
|
// The hash size of BLAKE2s-128 in bytes.
|
||||||
|
Size128 = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
var errKeySize = errors.New("blake2s: invalid key size")
|
var errKeySize = errors.New("blake2s: invalid key size")
|
||||||
|
@ -37,6 +41,17 @@ func Sum256(data []byte) [Size]byte {
|
||||||
// key turns the hash into a MAC. The key must between zero and 32 bytes long.
|
// key turns the hash into a MAC. The key must between zero and 32 bytes long.
|
||||||
func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
||||||
|
|
||||||
|
// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
|
||||||
|
// non-empty key. Note that a 128-bit digest is too small to be secure as a
|
||||||
|
// cryptographic hash and should only be used as a MAC, thus the key argument
|
||||||
|
// is not optional.
|
||||||
|
func New128(key []byte) (hash.Hash, error) {
|
||||||
|
if len(key) == 0 {
|
||||||
|
return nil, errors.New("blake2s: a key is required for a 128-bit hash")
|
||||||
|
}
|
||||||
|
return newDigest(Size128, key)
|
||||||
|
}
|
||||||
|
|
||||||
func newDigest(hashSize int, key []byte) (*digest, error) {
|
func newDigest(hashSize int, key []byte) (*digest, error) {
|
||||||
if len(key) > Size {
|
if len(key) > Size {
|
||||||
return nil, errKeySize
|
return nil, errKeySize
|
||||||
|
|
296
vendor/golang.org/x/crypto/blake2s/blake2s_test.go
generated
vendored
296
vendor/golang.org/x/crypto/blake2s/blake2s_test.go
generated
vendored
|
@ -18,21 +18,25 @@ func TestHashes(t *testing.T) {
|
||||||
if useSSE4 {
|
if useSSE4 {
|
||||||
t.Log("SSE4 version")
|
t.Log("SSE4 version")
|
||||||
testHashes(t)
|
testHashes(t)
|
||||||
|
testHashes128(t)
|
||||||
useSSE4 = false
|
useSSE4 = false
|
||||||
}
|
}
|
||||||
if useSSSE3 {
|
if useSSSE3 {
|
||||||
t.Log("SSSE3 version")
|
t.Log("SSSE3 version")
|
||||||
testHashes(t)
|
testHashes(t)
|
||||||
|
testHashes128(t)
|
||||||
useSSSE3 = false
|
useSSSE3 = false
|
||||||
}
|
}
|
||||||
if useSSE2 {
|
if useSSE2 {
|
||||||
t.Log("SSE2 version")
|
t.Log("SSE2 version")
|
||||||
testHashes(t)
|
testHashes(t)
|
||||||
|
testHashes128(t)
|
||||||
useSSE2 = false
|
useSSE2 = false
|
||||||
}
|
}
|
||||||
if useGeneric {
|
if useGeneric {
|
||||||
t.Log("generic version")
|
t.Log("generic version")
|
||||||
testHashes(t)
|
testHashes(t)
|
||||||
|
testHashes128(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +73,39 @@ func testHashes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testHashes128(t *testing.T) {
|
||||||
|
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
|
||||||
|
|
||||||
|
input := make([]byte, 255)
|
||||||
|
for i := range input {
|
||||||
|
input[i] = byte(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, expectedHex := range hashes128 {
|
||||||
|
h, err := New128(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("#%d: error from New128: %v", i, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Write(input[:i])
|
||||||
|
sum := h.Sum(nil)
|
||||||
|
|
||||||
|
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
|
||||||
|
t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Reset()
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
h.Write(input[j : j+1])
|
||||||
|
}
|
||||||
|
|
||||||
|
sum = h.Sum(sum[:0])
|
||||||
|
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
|
||||||
|
t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Benchmarks
|
// Benchmarks
|
||||||
|
|
||||||
func benchmarkSum(b *testing.B, size int) {
|
func benchmarkSum(b *testing.B, size int) {
|
||||||
|
@ -355,3 +392,262 @@ var hashes = []string{
|
||||||
"db444c15597b5f1a03d1f9edd16e4a9f43a667cc275175dfa2b704e3bb1a9b83",
|
"db444c15597b5f1a03d1f9edd16e4a9f43a667cc275175dfa2b704e3bb1a9b83",
|
||||||
"3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd",
|
"3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hashes128 = []string{
|
||||||
|
"9536f9b267655743dee97b8a670f9f53",
|
||||||
|
"13bacfb85b48a1223c595f8c1e7e82cb",
|
||||||
|
"d47a9b1645e2feae501cd5fe44ce6333",
|
||||||
|
"1e2a79436a7796a3e9826bfedf07659f",
|
||||||
|
"7640360ed3c4f3054dba79a21dda66b7",
|
||||||
|
"d1207ac2bf5ac84fc9ef016da5a46a86",
|
||||||
|
"3123987871e59305ece3125abfc0099a",
|
||||||
|
"cf9e072ad522f2cda2d825218086731c",
|
||||||
|
"95d22870392efe2846b12b6e8e84efbb",
|
||||||
|
"7d63c30e2d51333f245601b038c0b93b",
|
||||||
|
"ed608b98e13976bdf4bedc63fa35e443",
|
||||||
|
"ed704b5cd1abf8e0dd67a6ac667a3fa5",
|
||||||
|
"77dc70109827dc74c70fd26cba379ae5",
|
||||||
|
"d2bf34508b07825ee934f33958f4560e",
|
||||||
|
"a340baa7b8a93a6e658adef42e78eeb7",
|
||||||
|
"b85c5ceaecbe9a251eac76f6932ba395",
|
||||||
|
"246519722001f6e8e97a2183f5985e53",
|
||||||
|
"5bce5aa0b7c6cac2ecf6406183cd779a",
|
||||||
|
"13408f1647c02f6efd0047ad8344f695",
|
||||||
|
"a63970f196760aa36cb965ab62f0e0fa",
|
||||||
|
"bc26f48421dd99fd45e15e736d3e7dac",
|
||||||
|
"4c6f70f9e3237cde918afb52d26f1823",
|
||||||
|
"45ed610cfbc37db80c4bf0eef14ae8d6",
|
||||||
|
"87c4c150705ea5078209ec008200539c",
|
||||||
|
"54de21f5e0e6f2afe04daeb822b6931e",
|
||||||
|
"9732a04e505064e19de3d542e7e71631",
|
||||||
|
"d2bd27e95531d6957eef511c4ba64ad4",
|
||||||
|
"7a36c9f70dcc7c3063b547101a5f6c35",
|
||||||
|
"322007d1a44c4257bc7903b183305529",
|
||||||
|
"dbcc9a09f412290ca2e0d53dfd142ddb",
|
||||||
|
"df12ed43b8e53a56db20e0f83764002c",
|
||||||
|
"d114cc11e7d5b33a360c45f18d4c7c6e",
|
||||||
|
"c43b5e836af88620a8a71b1652cb8640",
|
||||||
|
"9491c653e8867ed73c1b4ac6b5a9bb4d",
|
||||||
|
"06d0e988df94ada6c6f9f36f588ab7c5",
|
||||||
|
"561efad2480e93262c8eeaa3677615c4",
|
||||||
|
"ba8ffc702e5adc93503045eca8702312",
|
||||||
|
"5782be6ccdc78c8425285e85de8ccdc6",
|
||||||
|
"aa1c4393e4c07b53ea6e2b5b1e970771",
|
||||||
|
"42a229dc50e52271c51e8666023ebc1e",
|
||||||
|
"53706110e919f84de7f8d6c7f0e7b831",
|
||||||
|
"fc5ac8ee39cc1dd1424391323e2901bd",
|
||||||
|
"bed27b62ff66cac2fbb68193c727106a",
|
||||||
|
"cd5e689b96d0b9ea7e08dac36f7b211e",
|
||||||
|
"0b4c7f604eba058d18e322c6e1baf173",
|
||||||
|
"eb838227fdfad09a27f0f8413120675d",
|
||||||
|
"3149cf9d19a7fd529e6154a8b4c3b3ad",
|
||||||
|
"ca1e20126df930fd5fb7afe4422191e5",
|
||||||
|
"b23398f910599f3c09b6549fa81bcb46",
|
||||||
|
"27fb17c11b34fa5d8b5afe5ee3321ead",
|
||||||
|
"0f665f5f04cf2d46b7fead1a1f328158",
|
||||||
|
"8f068be73b3681f99f3b282e3c02bba5",
|
||||||
|
"ba189bbd13808dcf4e002a4dd21660d5",
|
||||||
|
"2732dcd1b16668ae6ab6a61595d0d62a",
|
||||||
|
"d410ccdd059f0e02b472ec9ec54bdd3c",
|
||||||
|
"b2eaa07b055b3a03a399971327f7e8c2",
|
||||||
|
"2e8a225655e9f99b69c60dc8b4d8e566",
|
||||||
|
"4eb55416c853f2152e67f8a224133cec",
|
||||||
|
"49552403790d8de0505a8e317a443687",
|
||||||
|
"7f2747cd41f56942752e868212c7d5ac",
|
||||||
|
"02a28f10e193b430df7112d2d98cf759",
|
||||||
|
"d4213404a9f1cf759017747cf5958270",
|
||||||
|
"faa34884344f9c65e944882db8476d34",
|
||||||
|
"ece382a8bd5018f1de5da44b72cea75b",
|
||||||
|
"f1efa90d2547036841ecd3627fafbc36",
|
||||||
|
"811ff8686d23a435ecbd0bdafcd27b1b",
|
||||||
|
"b21beea9c7385f657a76558530438721",
|
||||||
|
"9cb969da4f1b4fc5b13bf78fe366f0c4",
|
||||||
|
"8850d16d7b614d3268ccfa009d33c7fc",
|
||||||
|
"aa98a2b6176ea86415b9aff3268c6f6d",
|
||||||
|
"ec3e1efa5ed195eff667e16b1af1e39e",
|
||||||
|
"e40787dca57411d2630db2de699beb08",
|
||||||
|
"554835890735babd06318de23d31e78a",
|
||||||
|
"493957feecddc302ee2bb2086b6ebfd3",
|
||||||
|
"f6069709ad5b0139163717e9ce1114ab",
|
||||||
|
"ba5ed386098da284484b211555505a01",
|
||||||
|
"9244c8dfad8cbb68c118fa51465b3ae4",
|
||||||
|
"51e309a5008eb1f5185e5cc007cfb36f",
|
||||||
|
"6ce9ff712121b4f6087955f4911eafd4",
|
||||||
|
"59b51d8dcda031218ccdd7c760828155",
|
||||||
|
"0012878767a3d4f1c8194458cf1f8832",
|
||||||
|
"82900708afd5b6582dc16f008c655edd",
|
||||||
|
"21302c7e39b5a4cdf1d6f86b4f00c9b4",
|
||||||
|
"e894c7431591eab8d1ce0fe2aa1f01df",
|
||||||
|
"b67e1c40ee9d988226d605621854d955",
|
||||||
|
"6237bdafa34137cbbec6be43ea9bd22c",
|
||||||
|
"4172a8e19b0dcb09b978bb9eff7af52b",
|
||||||
|
"5714abb55bd4448a5a6ad09fbd872fdf",
|
||||||
|
"7ce1700bef423e1f958a94a77a94d44a",
|
||||||
|
"3742ec50cded528527775833453e0b26",
|
||||||
|
"5d41b135724c7c9c689495324b162f18",
|
||||||
|
"85c523333c6442c202e9e6e0f1185f93",
|
||||||
|
"5c71f5222d40ff5d90e7570e71ab2d30",
|
||||||
|
"6e18912e83d012efb4c66250ced6f0d9",
|
||||||
|
"4add4448c2e35e0b138a0bac7b4b1775",
|
||||||
|
"c0376c6bc5e7b8b9d2108ec25d2aab53",
|
||||||
|
"f72261d5ed156765c977751c8a13fcc1",
|
||||||
|
"cff4156c48614b6ceed3dd6b9058f17e",
|
||||||
|
"36bfb513f76c15f514bcb593419835aa",
|
||||||
|
"166bf48c6bffaf8291e6fdf63854bef4",
|
||||||
|
"0b67d33f8b859c3157fbabd9e6e47ed0",
|
||||||
|
"e4da659ca76c88e73a9f9f10f3d51789",
|
||||||
|
"33c1ae2a86b3f51c0642e6ed5b5aa1f1",
|
||||||
|
"27469b56aca2334449c1cf4970dcd969",
|
||||||
|
"b7117b2e363378aa0901b0d6a9f6ddc0",
|
||||||
|
"a9578233b09e5cd5231943fdb12cd90d",
|
||||||
|
"486d7d75253598b716a068243c1c3e89",
|
||||||
|
"66f6b02d682b78ffdc85e9ec86852489",
|
||||||
|
"38a07b9a4b228fbcc305476e4d2e05d2",
|
||||||
|
"aedb61c7970e7d05bf9002dae3c6858c",
|
||||||
|
"c03ef441f7dd30fdb61ad2d4d8e4c7da",
|
||||||
|
"7f45cc1eea9a00cb6aeb2dd748361190",
|
||||||
|
"a59538b358459132e55160899e47bd65",
|
||||||
|
"137010fef72364411820c3fbed15c8df",
|
||||||
|
"d8362b93fc504500dbd33ac74e1b4d70",
|
||||||
|
"a7e49f12c8f47e3b29cf8c0889b0a9c8",
|
||||||
|
"072e94ffbfc684bd8ab2a1b9dade2fd5",
|
||||||
|
"5ab438584bd2229e452052e002631a5f",
|
||||||
|
"f233d14221097baef57d3ec205c9e086",
|
||||||
|
"3a95db000c4a8ff98dc5c89631a7f162",
|
||||||
|
"0544f18c2994ab4ddf1728f66041ff16",
|
||||||
|
"0bc02116c60a3cc331928d6c9d3ba37e",
|
||||||
|
"b189dca6cb5b813c74200834fba97f29",
|
||||||
|
"ac8aaab075b4a5bc24419da239212650",
|
||||||
|
"1e9f19323dc71c29ae99c479dc7e8df9",
|
||||||
|
"12d944c3fa7caa1b3d62adfc492274dd",
|
||||||
|
"b4c68f1fffe8f0030e9b18aad8c9dc96",
|
||||||
|
"25887fab1422700d7fa3edc0b20206e2",
|
||||||
|
"8c09f698d03eaf88abf69f8147865ef6",
|
||||||
|
"5c363ae42a5bec26fbc5e996428d9bd7",
|
||||||
|
"7fdfc2e854fbb3928150d5e3abcf56d6",
|
||||||
|
"f0c944023f714df115f9e4f25bcdb89b",
|
||||||
|
"6d19534b4c332741c8ddd79a9644de2d",
|
||||||
|
"32595eb23764fbfc2ee7822649f74a12",
|
||||||
|
"5a51391aab33c8d575019b6e76ae052a",
|
||||||
|
"98b861ce2c620f10f913af5d704a5afd",
|
||||||
|
"b7fe2fc8b77fb1ce434f8465c7ddf793",
|
||||||
|
"0e8406e0cf8e9cc840668ece2a0fc64e",
|
||||||
|
"b89922db99c58f6a128ccffe19b6ce60",
|
||||||
|
"e1be9af665f0932b77d7f5631a511db7",
|
||||||
|
"74b96f20f58de8dc9ff5e31f91828523",
|
||||||
|
"36a4cfef5a2a7d8548db6710e50b3009",
|
||||||
|
"007e95e8d3b91948a1dedb91f75de76b",
|
||||||
|
"a87a702ce08f5745edf765bfcd5fbe0d",
|
||||||
|
"847e69a388a749a9c507354d0dddfe09",
|
||||||
|
"07176eefbc107a78f058f3d424ca6a54",
|
||||||
|
"ad7e80682333b68296f6cb2b4a8e446d",
|
||||||
|
"53c4aba43896ae422e5de5b9edbd46bf",
|
||||||
|
"33bd6c20ca2a7ab916d6e98003c6c5f8",
|
||||||
|
"060d088ea94aa093f9981a79df1dfcc8",
|
||||||
|
"5617b214b9df08d4f11e58f5e76d9a56",
|
||||||
|
"ca3a60ee85bd971e1daf9f7db059d909",
|
||||||
|
"cd2b7754505d8c884eddf736f1ec613e",
|
||||||
|
"f496163b252f1439e7e113ba2ecabd8e",
|
||||||
|
"5719c7dcf9d9f756d6213354acb7d5cf",
|
||||||
|
"6f7dd40b245c54411e7a9be83ae5701c",
|
||||||
|
"c8994dd9fdeb077a45ea04a30358b637",
|
||||||
|
"4b1184f1e35458c1c747817d527a252f",
|
||||||
|
"fc7df674afeac7a3fd994183f4c67a74",
|
||||||
|
"4f68e05ce4dcc533acf9c7c01d95711e",
|
||||||
|
"d4ebc59e918400720035dfc88e0c486a",
|
||||||
|
"d3105dd6fa123e543b0b3a6e0eeaea9e",
|
||||||
|
"874196128ed443f5bdb2800ca048fcad",
|
||||||
|
"01645f134978dc8f9cf0abc93b53780e",
|
||||||
|
"5b8b64caa257873a0ffd47c981ef6c3f",
|
||||||
|
"4ee208fc50ba0a6e65c5b58cec44c923",
|
||||||
|
"53f409a52427b3b7ffabb057ca088428",
|
||||||
|
"c1d6cd616f5341a93d921e356e5887a9",
|
||||||
|
"e85c20fea67fa7320dc23379181183c8",
|
||||||
|
"7912b6409489df001b7372bc94aebde7",
|
||||||
|
"e559f761ec866a87f1f331767fafc60f",
|
||||||
|
"20a6f5a36bc37043d977ed7708465ef8",
|
||||||
|
"6a72f526965ab120826640dd784c6cc4",
|
||||||
|
"bf486d92ad68e87c613689dd370d001b",
|
||||||
|
"d339fd0eb35edf3abd6419c8d857acaf",
|
||||||
|
"9521cd7f32306d969ddabc4e6a617f52",
|
||||||
|
"a1cd9f3e81520842f3cf6cc301cb0021",
|
||||||
|
"18e879b6f154492d593edd3f4554e237",
|
||||||
|
"66e2329c1f5137589e051592587e521e",
|
||||||
|
"e899566dd6c3e82cbc83958e69feb590",
|
||||||
|
"8a4b41d7c47e4e80659d77b4e4bfc9ae",
|
||||||
|
"f1944f6fcfc17803405a1101998c57dd",
|
||||||
|
"f6bcec07567b4f72851b307139656b18",
|
||||||
|
"22e7bb256918fe9924dce9093e2d8a27",
|
||||||
|
"dd25b925815fe7b50b7079f5f65a3970",
|
||||||
|
"0457f10f299acf0c230dd4007612e58f",
|
||||||
|
"ecb420c19efd93814fae2964d69b54af",
|
||||||
|
"14eb47b06dff685d88751c6e32789db4",
|
||||||
|
"e8f072dbb50d1ab6654aa162604a892d",
|
||||||
|
"69cff9c62092332f03a166c7b0034469",
|
||||||
|
"d3619f98970b798ca32c6c14cd25af91",
|
||||||
|
"2246d423774ee9d51a551e89c0539d9e",
|
||||||
|
"75e5d1a1e374a04a699247dad827b6cf",
|
||||||
|
"6d087dd1d4cd15bf47db07c7a96b1db8",
|
||||||
|
"967e4c055ac51b4b2a3e506cebd5826f",
|
||||||
|
"7417aa79247e473401bfa92a25b62e2a",
|
||||||
|
"24f3f4956da34b5c533d9a551ccd7b16",
|
||||||
|
"0c40382de693a5304e2331eb951cc962",
|
||||||
|
"9436f949d51b347db5c8e6258dafaaac",
|
||||||
|
"d2084297fe84c4ba6e04e4fb73d734fe",
|
||||||
|
"42a6f8ff590af21b512e9e088257aa34",
|
||||||
|
"c484ad06b1cdb3a54f3f6464a7a2a6fd",
|
||||||
|
"1b8ac860f5ceb4365400a201ed2917aa",
|
||||||
|
"c43eadabbe7b7473f3f837fc52650f54",
|
||||||
|
"0e5d3205406126b1f838875deb150d6a",
|
||||||
|
"6bf4946f8ec8a9c417f50cd1e67565be",
|
||||||
|
"42f09a2522314799c95b3fc121a0e3e8",
|
||||||
|
"06b8f1487f691a3f7c3f74e133d55870",
|
||||||
|
"1a70a65fb4f314dcf6a31451a9d2704f",
|
||||||
|
"7d4acdd0823279fd28a1e48b49a04669",
|
||||||
|
"09545cc8822a5dfc93bbab708fd69174",
|
||||||
|
"efc063db625013a83c9a426d39a9bddb",
|
||||||
|
"213bbf89b3f5be0ffdb14854bbcb2588",
|
||||||
|
"b69624d89fe2774df9a6f43695d755d4",
|
||||||
|
"c0f9ff9ded82bd73c512e365a894774d",
|
||||||
|
"d1b68507ed89c17ead6f69012982db71",
|
||||||
|
"14cf16db04648978e35c44850855d1b0",
|
||||||
|
"9f254d4eccab74cd91d694df863650a8",
|
||||||
|
"8f8946e2967baa4a814d36ff01d20813",
|
||||||
|
"6b9dc4d24ecba166cb2915d7a6cba43b",
|
||||||
|
"eb35a80418a0042b850e294db7898d4d",
|
||||||
|
"f55f925d280c637d54055c9df088ef5f",
|
||||||
|
"f48427a04f67e33f3ba0a17f7c9704a7",
|
||||||
|
"4a9f5bfcc0321aea2eced896cee65894",
|
||||||
|
"8723a67d1a1df90f1cef96e6fe81e702",
|
||||||
|
"c166c343ee25998f80bad4067960d3fd",
|
||||||
|
"dab67288d16702e676a040fd42344d73",
|
||||||
|
"c8e9e0d80841eb2c116dd14c180e006c",
|
||||||
|
"92294f546bacf0dea9042c93ecba8b34",
|
||||||
|
"013705b1502b37369ad22fe8237d444e",
|
||||||
|
"9b97f8837d5f2ebab0768fc9a6446b93",
|
||||||
|
"7e7e5236b05ec35f89edf8bf655498e7",
|
||||||
|
"7be8f2362c174c776fb9432fe93bf259",
|
||||||
|
"2422e80420276d2df5702c6470879b01",
|
||||||
|
"df645795db778bcce23bbe819a76ba48",
|
||||||
|
"3f97a4ac87dfc58761cda1782d749074",
|
||||||
|
"50e3f45df21ebfa1b706b9c0a1c245a8",
|
||||||
|
"7879541c7ff612c7ddf17cb8f7260183",
|
||||||
|
"67f6542b903b7ba1945eba1a85ee6b1c",
|
||||||
|
"b34b73d36ab6234b8d3f5494d251138e",
|
||||||
|
"0aea139641fdba59ab1103479a96e05f",
|
||||||
|
"02776815a87b8ba878453666d42afe3c",
|
||||||
|
"5929ab0a90459ebac5a16e2fb37c847e",
|
||||||
|
"c244def5b20ce0468f2b5012d04ac7fd",
|
||||||
|
"12116add6fefce36ed8a0aeccce9b6d3",
|
||||||
|
"3cd743841e9d8b878f34d91b793b4fad",
|
||||||
|
"45e87510cf5705262185f46905fae35f",
|
||||||
|
"276047016b0bfb501b2d4fc748165793",
|
||||||
|
"ddd245df5a799417d350bd7f4e0b0b7e",
|
||||||
|
"d34d917a54a2983f3fdbc4b14caae382",
|
||||||
|
"7730fbc09d0c1fb1939a8fc436f6b995",
|
||||||
|
"eb4899ef257a1711cc9270a19702e5b5",
|
||||||
|
"8a30932014bce35bba620895d374df7a",
|
||||||
|
"1924aabf9c50aa00bee5e1f95b5d9e12",
|
||||||
|
"1758d6f8b982aec9fbe50f20e3082b46",
|
||||||
|
"cd075928ab7e6883e697fe7fd3ac43ee",
|
||||||
|
}
|
||||||
|
|
21
vendor/golang.org/x/crypto/blake2s/register.go
generated
vendored
Normal file
21
vendor/golang.org/x/crypto/blake2s/register.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package blake2s
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
newHash256 := func() hash.Hash {
|
||||||
|
h, _ := New256(nil)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto.RegisterHash(crypto.BLAKE2s_256, newHash256)
|
||||||
|
}
|
2
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
generated
vendored
2
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go
generated
vendored
|
@ -3,7 +3,7 @@
|
||||||
// license that can be found in the LICENSE file.
|
// 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.
|
||||||
package chacha20poly1305
|
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
|
59
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
59
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
|
@ -14,13 +14,60 @@ func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
||||||
|
|
||||||
//go:noescape
|
// cpuid is implemented in chacha20poly1305_amd64.s.
|
||||||
func haveSSSE3() bool
|
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||||
|
|
||||||
var canUseASM bool
|
// xgetbv with ecx = 0 is implemented in chacha20poly1305_amd64.s.
|
||||||
|
func xgetbv() (eax, edx uint32)
|
||||||
|
|
||||||
|
var (
|
||||||
|
useASM bool
|
||||||
|
useAVX2 bool
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
canUseASM = haveSSSE3()
|
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
|
// setupState writes a ChaCha20 input matrix to state. See
|
||||||
|
@ -47,7 +94,7 @@ func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||||
if !canUseASM {
|
if !useASM {
|
||||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +107,7 @@ func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||||
if !canUseASM {
|
if !useASM {
|
||||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
45
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
|
@ -278,15 +278,8 @@ TEXT ·chacha20Poly1305Open(SB), 0, $288-97
|
||||||
MOVQ ad+72(FP), adp
|
MOVQ ad+72(FP), adp
|
||||||
|
|
||||||
// Check for AVX2 support
|
// Check for AVX2 support
|
||||||
CMPB runtime·support_avx2(SB), $0
|
CMPB ·useAVX2(SB), $1
|
||||||
JE noavx2bmi2Open
|
JE chacha20Poly1305Open_AVX2
|
||||||
|
|
||||||
// Check BMI2 bit for MULXQ.
|
|
||||||
// runtime·cpuid_ebx7 is always available here
|
|
||||||
// because it passed avx2 check
|
|
||||||
TESTL $(1<<8), runtime·cpuid_ebx7(SB)
|
|
||||||
JNE chacha20Poly1305Open_AVX2
|
|
||||||
noavx2bmi2Open:
|
|
||||||
|
|
||||||
// Special optimization, for very short buffers
|
// Special optimization, for very short buffers
|
||||||
CMPQ inl, $128
|
CMPQ inl, $128
|
||||||
|
@ -1491,16 +1484,8 @@ TEXT ·chacha20Poly1305Seal(SB), 0, $288-96
|
||||||
MOVQ src_len+56(FP), inl
|
MOVQ src_len+56(FP), inl
|
||||||
MOVQ ad+72(FP), adp
|
MOVQ ad+72(FP), adp
|
||||||
|
|
||||||
// Check for AVX2 support
|
CMPB ·useAVX2(SB), $1
|
||||||
CMPB runtime·support_avx2(SB), $0
|
JE chacha20Poly1305Seal_AVX2
|
||||||
JE noavx2bmi2Seal
|
|
||||||
|
|
||||||
// Check BMI2 bit for MULXQ.
|
|
||||||
// runtime·cpuid_ebx7 is always available here
|
|
||||||
// because it passed avx2 check
|
|
||||||
TESTL $(1<<8), runtime·cpuid_ebx7(SB)
|
|
||||||
JNE chacha20Poly1305Seal_AVX2
|
|
||||||
noavx2bmi2Seal:
|
|
||||||
|
|
||||||
// Special optimization, for very short buffers
|
// Special optimization, for very short buffers
|
||||||
CMPQ inl, $128
|
CMPQ inl, $128
|
||||||
|
@ -2709,13 +2694,21 @@ sealAVX2Tail512LoopB:
|
||||||
|
|
||||||
JMP sealAVX2SealHash
|
JMP sealAVX2SealHash
|
||||||
|
|
||||||
// func haveSSSE3() bool
|
// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||||
TEXT ·haveSSSE3(SB), NOSPLIT, $0
|
TEXT ·cpuid(SB), NOSPLIT, $0-24
|
||||||
XORQ AX, AX
|
MOVL eaxArg+0(FP), AX
|
||||||
INCL AX
|
MOVL ecxArg+4(FP), CX
|
||||||
CPUID
|
CPUID
|
||||||
SHRQ $9, CX
|
MOVL AX, eax+8(FP)
|
||||||
ANDQ $1, CX
|
MOVL BX, ebx+12(FP)
|
||||||
MOVB CX, ret+0(FP)
|
MOVL CX, ecx+16(FP)
|
||||||
|
MOVL DX, edx+20(FP)
|
||||||
RET
|
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
|
||||||
|
|
4
vendor/golang.org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
generated
vendored
4
vendor/golang.org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
generated
vendored
|
@ -1,3 +1,7 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package chacha20
|
package chacha20
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
604
vendor/golang.org/x/crypto/cryptobyte/asn1.go
generated
vendored
Normal file
604
vendor/golang.org/x/crypto/cryptobyte/asn1.go
generated
vendored
Normal file
|
@ -0,0 +1,604 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cryptobyte
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/asn1"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file contains ASN.1-related methods for String and Builder.
|
||||||
|
|
||||||
|
// Tag represents an ASN.1 tag number and class (together also referred to as
|
||||||
|
// identifier octets). Methods in this package only support the low-tag-number
|
||||||
|
// form, i.e. a single identifier octet with bits 7-8 encoding the class and
|
||||||
|
// bits 1-6 encoding the tag number.
|
||||||
|
type Tag uint8
|
||||||
|
|
||||||
|
// Contructed returns t with the context-specific class bit set.
|
||||||
|
func (t Tag) ContextSpecific() Tag { return t | 0x80 }
|
||||||
|
|
||||||
|
// Contructed returns t with the constructed class bit set.
|
||||||
|
func (t Tag) Constructed() Tag { return t | 0x20 }
|
||||||
|
|
||||||
|
// Builder
|
||||||
|
|
||||||
|
// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
|
||||||
|
func (b *Builder) AddASN1Int64(v int64) {
|
||||||
|
b.addASN1Signed(asn1.TagInteger, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
|
||||||
|
func (b *Builder) AddASN1Enum(v int64) {
|
||||||
|
b.addASN1Signed(asn1.TagEnum, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) addASN1Signed(tag Tag, v int64) {
|
||||||
|
b.AddASN1(tag, func(c *Builder) {
|
||||||
|
length := 1
|
||||||
|
for i := v; i >= 0x80 || i < -0x80; i >>= 8 {
|
||||||
|
length++
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; length > 0; length-- {
|
||||||
|
i := v >> uint((length-1)*8) & 0xff
|
||||||
|
c.AddUint8(uint8(i))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
|
||||||
|
func (b *Builder) AddASN1Uint64(v uint64) {
|
||||||
|
b.AddASN1(asn1.TagInteger, func(c *Builder) {
|
||||||
|
length := 1
|
||||||
|
for i := v; i >= 0x80; i >>= 8 {
|
||||||
|
length++
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; length > 0; length-- {
|
||||||
|
i := v >> uint((length-1)*8) & 0xff
|
||||||
|
c.AddUint8(uint8(i))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
|
||||||
|
func (b *Builder) AddASN1BigInt(n *big.Int) {
|
||||||
|
if b.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b.AddASN1(asn1.TagInteger, func(c *Builder) {
|
||||||
|
if n.Sign() < 0 {
|
||||||
|
// A negative number has to be converted to two's-complement form. So we
|
||||||
|
// invert and subtract 1. If the most-significant-bit isn't set then
|
||||||
|
// we'll need to pad the beginning with 0xff in order to keep the number
|
||||||
|
// negative.
|
||||||
|
nMinus1 := new(big.Int).Neg(n)
|
||||||
|
nMinus1.Sub(nMinus1, bigOne)
|
||||||
|
bytes := nMinus1.Bytes()
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[i] ^= 0xff
|
||||||
|
}
|
||||||
|
if bytes[0]&0x80 == 0 {
|
||||||
|
c.add(0xff)
|
||||||
|
}
|
||||||
|
c.add(bytes...)
|
||||||
|
} else if n.Sign() == 0 {
|
||||||
|
c.add(0)
|
||||||
|
} else {
|
||||||
|
bytes := n.Bytes()
|
||||||
|
if bytes[0]&0x80 != 0 {
|
||||||
|
c.add(0)
|
||||||
|
}
|
||||||
|
c.add(bytes...)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
|
||||||
|
func (b *Builder) AddASN1OctetString(bytes []byte) {
|
||||||
|
b.AddASN1(asn1.TagOctetString, func(c *Builder) {
|
||||||
|
c.AddBytes(bytes)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const generalizedTimeFormatStr = "20060102150405Z0700"
|
||||||
|
|
||||||
|
// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
|
||||||
|
func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
|
||||||
|
if t.Year() < 0 || t.Year() > 9999 {
|
||||||
|
b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.AddASN1(asn1.TagGeneralizedTime, func(c *Builder) {
|
||||||
|
c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING.
|
||||||
|
func (b *Builder) AddASN1BitString(s asn1.BitString) {
|
||||||
|
// TODO(martinkr): Implement.
|
||||||
|
b.MarshalASN1(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalASN1 calls asn1.Marshal on its input and appends the result if
|
||||||
|
// successful or records an error if one occurred.
|
||||||
|
func (b *Builder) MarshalASN1(v interface{}) {
|
||||||
|
// NOTE(martinkr): This is somewhat of a hack to allow propagation of
|
||||||
|
// asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a
|
||||||
|
// value embedded into a struct, its tag information is lost.
|
||||||
|
if b.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bytes, err := asn1.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
b.err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.AddBytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag.
|
||||||
|
// Tags greater than 30 are not supported and result in an error (i.e.
|
||||||
|
// low-tag-number form only). The child builder passed to the
|
||||||
|
// BuilderContinuation can be used to build the content of the ASN.1 object.
|
||||||
|
func (b *Builder) AddASN1(tag Tag, f BuilderContinuation) {
|
||||||
|
if b.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Identifiers with the low five bits set indicate high-tag-number format
|
||||||
|
// (two or more octets), which we don't support.
|
||||||
|
if tag&0x1f == 0x1f {
|
||||||
|
b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.AddUint8(uint8(tag))
|
||||||
|
b.addLengthPrefixed(1, true, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String
|
||||||
|
|
||||||
|
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.
|
||||||
|
func (s *String) ReadASN1Integer(out interface{}) bool {
|
||||||
|
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||||
|
panic("out is not a pointer")
|
||||||
|
}
|
||||||
|
switch reflect.ValueOf(out).Elem().Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
var i int64
|
||||||
|
if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
reflect.ValueOf(out).Elem().SetInt(i)
|
||||||
|
return true
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
var u uint64
|
||||||
|
if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
reflect.ValueOf(out).Elem().SetUint(u)
|
||||||
|
return true
|
||||||
|
case reflect.Struct:
|
||||||
|
if reflect.TypeOf(out).Elem() == bigIntType {
|
||||||
|
return s.readASN1BigInt(out.(*big.Int))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("out does not point to an integer type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkASN1Integer(bytes []byte) bool {
|
||||||
|
if len(bytes) == 0 {
|
||||||
|
// An INTEGER is encoded with at least one octet.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(bytes) == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 {
|
||||||
|
// Value is not minimally encoded.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var bigOne = big.NewInt(1)
|
||||||
|
|
||||||
|
func (s *String) readASN1BigInt(out *big.Int) bool {
|
||||||
|
var bytes String
|
||||||
|
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if bytes[0]&0x80 == 0x80 {
|
||||||
|
// Negative number.
|
||||||
|
neg := make([]byte, len(bytes))
|
||||||
|
for i, b := range bytes {
|
||||||
|
neg[i] = ^b
|
||||||
|
}
|
||||||
|
out.SetBytes(neg)
|
||||||
|
out.Add(out, bigOne)
|
||||||
|
out.Neg(out)
|
||||||
|
} else {
|
||||||
|
out.SetBytes(bytes)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *String) readASN1Int64(out *int64) bool {
|
||||||
|
var bytes String
|
||||||
|
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func asn1Signed(out *int64, n []byte) bool {
|
||||||
|
length := len(n)
|
||||||
|
if length > 8 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
*out <<= 8
|
||||||
|
*out |= int64(n[i])
|
||||||
|
}
|
||||||
|
// Shift up and down in order to sign extend the result.
|
||||||
|
*out <<= 64 - uint8(length)*8
|
||||||
|
*out >>= 64 - uint8(length)*8
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *String) readASN1Uint64(out *uint64) bool {
|
||||||
|
var bytes String
|
||||||
|
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func asn1Unsigned(out *uint64, n []byte) bool {
|
||||||
|
length := len(n)
|
||||||
|
if length > 9 || length == 9 && n[0] != 0 {
|
||||||
|
// Too large for uint64.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if n[0]&0x80 != 0 {
|
||||||
|
// Negative number.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
*out <<= 8
|
||||||
|
*out |= uint64(n[i])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns
|
||||||
|
// true on success and false on error.
|
||||||
|
func (s *String) ReadASN1Enum(out *int) bool {
|
||||||
|
var bytes String
|
||||||
|
var i int64
|
||||||
|
if !s.ReadASN1(&bytes, asn1.TagEnum) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if int64(int(i)) != i {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = int(i)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *String) readBase128Int(out *int) bool {
|
||||||
|
ret := 0
|
||||||
|
for i := 0; len(*s) > 0; i++ {
|
||||||
|
if i == 4 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ret <<= 7
|
||||||
|
b := s.read(1)[0]
|
||||||
|
ret |= int(b & 0x7f)
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
*out = ret
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false // truncated
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
|
||||||
|
// advances. It returns true on success and false on error.
|
||||||
|
func (s *String) ReadASN1ObjectIdentifier(out *asn1.ObjectIdentifier) bool {
|
||||||
|
var bytes String
|
||||||
|
if !s.ReadASN1(&bytes, asn1.TagOID) || len(bytes) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the worst case, we get two elements from the first byte (which is
|
||||||
|
// encoded differently) and then every varint is a single byte long.
|
||||||
|
components := make([]int, len(bytes)+1)
|
||||||
|
|
||||||
|
// The first varint is 40*value1 + value2:
|
||||||
|
// According to this packing, value1 can take the values 0, 1 and 2 only.
|
||||||
|
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
||||||
|
// then there are no restrictions on value2.
|
||||||
|
var v int
|
||||||
|
if !bytes.readBase128Int(&v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if v < 80 {
|
||||||
|
components[0] = v / 40
|
||||||
|
components[1] = v % 40
|
||||||
|
} else {
|
||||||
|
components[0] = 2
|
||||||
|
components[1] = v - 80
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 2
|
||||||
|
for ; len(bytes) > 0; i++ {
|
||||||
|
if !bytes.readBase128Int(&v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
components[i] = v
|
||||||
|
}
|
||||||
|
*out = components[:i]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
|
||||||
|
// advances. It returns true on success and false on error.
|
||||||
|
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
|
||||||
|
var bytes String
|
||||||
|
if !s.ReadASN1(&bytes, asn1.TagGeneralizedTime) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
t := string(bytes)
|
||||||
|
res, err := time.Parse(generalizedTimeFormatStr, t)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if serialized := res.Format(generalizedTimeFormatStr); serialized != t {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = res
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It
|
||||||
|
// returns true on success and false on error.
|
||||||
|
func (s *String) ReadASN1BitString(out *asn1.BitString) bool {
|
||||||
|
var bytes String
|
||||||
|
if !s.ReadASN1(&bytes, asn1.TagBitString) || len(bytes) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
paddingBits := uint8(bytes[0])
|
||||||
|
bytes = bytes[1:]
|
||||||
|
if paddingBits > 7 ||
|
||||||
|
len(bytes) == 0 && paddingBits != 0 ||
|
||||||
|
len(bytes) > 0 && bytes[len(bytes)-1]&(1<<paddingBits-1) != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
out.BitLength = len(bytes)*8 - int(paddingBits)
|
||||||
|
out.Bytes = bytes
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (s *String) ReadASN1Bytes(out *[]byte, tag 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.
|
||||||
|
//
|
||||||
|
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||||
|
func (s *String) ReadASN1(out *String, tag Tag) bool {
|
||||||
|
var t Tag
|
||||||
|
if !s.ReadAnyASN1(out, &t) || t != tag {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||||
|
func (s *String) ReadASN1Element(out *String, tag Tag) bool {
|
||||||
|
var t Tag
|
||||||
|
if !s.ReadAnyASN1Element(out, &t) || t != tag {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||||
|
func (s *String) ReadAnyASN1(out *String, outTag *Tag) bool {
|
||||||
|
return s.readASN1(out, outTag, true /* skip header */)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||||
|
func (s *String) ReadAnyASN1Element(out *String, outTag *Tag) bool {
|
||||||
|
return s.readASN1(out, outTag, false /* include header */)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeekASN1Tag returns true if the next ASN.1 value on the string starts with
|
||||||
|
// the given tag.
|
||||||
|
func (s String) PeekASN1Tag(tag Tag) bool {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return Tag(s[0]) == tag
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.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.
|
||||||
|
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag Tag) bool {
|
||||||
|
present := s.PeekASN1Tag(tag)
|
||||||
|
if outPresent != nil {
|
||||||
|
*outPresent = present
|
||||||
|
}
|
||||||
|
if present && !s.ReadASN1(out, tag) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (s *String) ReadOptionalASN1Integer(out interface{}, tag Tag, defaultValue interface{}) bool {
|
||||||
|
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||||
|
panic("out is not a pointer")
|
||||||
|
}
|
||||||
|
var present bool
|
||||||
|
var i String
|
||||||
|
if !s.ReadOptionalASN1(&i, &present, tag) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !present {
|
||||||
|
switch reflect.ValueOf(out).Elem().Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue))
|
||||||
|
case reflect.Struct:
|
||||||
|
if reflect.TypeOf(out).Elem() != bigIntType {
|
||||||
|
panic("invalid integer type")
|
||||||
|
}
|
||||||
|
if reflect.TypeOf(defaultValue).Kind() != reflect.Ptr ||
|
||||||
|
reflect.TypeOf(defaultValue).Elem() != bigIntType {
|
||||||
|
panic("out points to big.Int, but defaultValue does not")
|
||||||
|
}
|
||||||
|
out.(*big.Int).Set(defaultValue.(*big.Int))
|
||||||
|
default:
|
||||||
|
panic("invalid integer type")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !i.ReadASN1Integer(out) || !i.Empty() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag Tag) bool {
|
||||||
|
var present bool
|
||||||
|
var child String
|
||||||
|
if !s.ReadOptionalASN1(&child, &present, tag) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if outPresent != nil {
|
||||||
|
*outPresent = present
|
||||||
|
}
|
||||||
|
if present {
|
||||||
|
var oct String
|
||||||
|
if !child.ReadASN1(&oct, asn1.TagOctetString) || !child.Empty() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = oct
|
||||||
|
} else {
|
||||||
|
*out = nil
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *String) readASN1(out *String, outTag *Tag, skipHeader bool) bool {
|
||||||
|
if len(*s) < 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tag, lenByte := (*s)[0], (*s)[1]
|
||||||
|
|
||||||
|
if tag&0x1f == 0x1f {
|
||||||
|
// ITU-T X.690 section 8.1.2
|
||||||
|
//
|
||||||
|
// An identifier octet with a tag part of 0x1f indicates a high-tag-number
|
||||||
|
// form identifier with two or more octets. We only support tags less than
|
||||||
|
// 31 (i.e. low-tag-number form, single octet identifier).
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if outTag != nil {
|
||||||
|
*outTag = Tag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ITU-T X.690 section 8.1.3
|
||||||
|
//
|
||||||
|
// Bit 8 of the first length byte indicates whether the length is short- or
|
||||||
|
// long-form.
|
||||||
|
var length, headerLen uint32 // length includes headerLen
|
||||||
|
if lenByte&0x80 == 0 {
|
||||||
|
// Short-form length (section 8.1.3.4), encoded in bits 1-7.
|
||||||
|
length = uint32(lenByte) + 2
|
||||||
|
headerLen = 2
|
||||||
|
} else {
|
||||||
|
// Long-form length (section 8.1.3.5). Bits 1-7 encode the number of octets
|
||||||
|
// used to encode the length.
|
||||||
|
lenLen := lenByte & 0x7f
|
||||||
|
var len32 uint32
|
||||||
|
|
||||||
|
if lenLen == 0 || lenLen > 4 || len(*s) < int(2+lenLen) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
lenBytes := String((*s)[2 : 2+lenLen])
|
||||||
|
if !lenBytes.readUnsigned(&len32, int(lenLen)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
|
||||||
|
// with the minimum number of octets.
|
||||||
|
if len32 < 128 {
|
||||||
|
// Length should have used short-form encoding.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len32>>((lenLen-1)*8) == 0 {
|
||||||
|
// Leading octet is 0. Length should have been at least one byte shorter.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
headerLen = 2 + uint32(lenLen)
|
||||||
|
if headerLen+len32 < len32 {
|
||||||
|
// Overflow.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
length = headerLen + len32
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint32(int(length)) != length || !s.ReadBytes((*[]byte)(out), int(length)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if skipHeader && !out.Skip(int(headerLen)) {
|
||||||
|
panic("cryptobyte: internal error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
285
vendor/golang.org/x/crypto/cryptobyte/asn1_test.go
generated
vendored
Normal file
285
vendor/golang.org/x/crypto/cryptobyte/asn1_test.go
generated
vendored
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cryptobyte
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/asn1"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type readASN1Test struct {
|
||||||
|
name string
|
||||||
|
in []byte
|
||||||
|
tag Tag
|
||||||
|
ok bool
|
||||||
|
out interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var readASN1TestData = []readASN1Test{
|
||||||
|
{"valid", []byte{0x30, 2, 1, 2}, 0x30, true, []byte{1, 2}},
|
||||||
|
{"truncated", []byte{0x30, 3, 1, 2}, 0x30, false, nil},
|
||||||
|
{"zero length of length", []byte{0x30, 0x80}, 0x30, false, nil},
|
||||||
|
{"invalid long form length", []byte{0x30, 0x81, 1, 1}, 0x30, false, nil},
|
||||||
|
{"non-minimal length", append([]byte{0x30, 0x82, 0, 0x80}, make([]byte, 0x80)...), 0x30, false, nil},
|
||||||
|
{"invalid tag", []byte{0xa1, 3, 0x4, 1, 1}, 31, false, nil},
|
||||||
|
{"high tag", []byte{0x1f, 0x81, 0x80, 0x01, 2, 1, 2}, 0xff /* actually 0x4001, but tag is uint8 */, false, nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1(t *testing.T) {
|
||||||
|
for _, test := range readASN1TestData {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
var in, out String = test.in, nil
|
||||||
|
ok := in.ReadASN1(&out, test.tag)
|
||||||
|
if ok != test.ok || ok && !bytes.Equal(out, test.out.([]byte)) {
|
||||||
|
t.Errorf("in.ReadASN1() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1Optional(t *testing.T) {
|
||||||
|
var empty String
|
||||||
|
var present bool
|
||||||
|
ok := empty.ReadOptionalASN1(nil, &present, 0xa0)
|
||||||
|
if !ok || present {
|
||||||
|
t.Errorf("empty.ReadOptionalASN1() = %v, want true; present = %v want false", ok, present)
|
||||||
|
}
|
||||||
|
|
||||||
|
var in, out String = []byte{0xa1, 3, 0x4, 1, 1}, nil
|
||||||
|
ok = in.ReadOptionalASN1(&out, &present, 0xa0)
|
||||||
|
if !ok || present {
|
||||||
|
t.Errorf("in.ReadOptionalASN1() = %v, want true, present = %v, want false", ok, present)
|
||||||
|
}
|
||||||
|
ok = in.ReadOptionalASN1(&out, &present, 0xa1)
|
||||||
|
wantBytes := []byte{4, 1, 1}
|
||||||
|
if !ok || !present || !bytes.Equal(out, wantBytes) {
|
||||||
|
t.Errorf("in.ReadOptionalASN1() = %v, want true; present = %v, want true; out = %v, want = %v", ok, present, out, wantBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var optionalOctetStringTestData = []struct {
|
||||||
|
readASN1Test
|
||||||
|
present bool
|
||||||
|
}{
|
||||||
|
{readASN1Test{"empty", []byte{}, 0xa0, true, []byte{}}, false},
|
||||||
|
{readASN1Test{"invalid", []byte{0xa1, 3, 0x4, 2, 1}, 0xa1, false, []byte{}}, true},
|
||||||
|
{readASN1Test{"missing", []byte{0xa1, 3, 0x4, 1, 1}, 0xa0, true, []byte{}}, false},
|
||||||
|
{readASN1Test{"present", []byte{0xa1, 3, 0x4, 1, 1}, 0xa1, true, []byte{1}}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1OptionalOctetString(t *testing.T) {
|
||||||
|
for _, test := range optionalOctetStringTestData {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
in := String(test.in)
|
||||||
|
var out []byte
|
||||||
|
var present bool
|
||||||
|
ok := in.ReadOptionalASN1OctetString(&out, &present, test.tag)
|
||||||
|
if ok != test.ok || present != test.present || !bytes.Equal(out, test.out.([]byte)) {
|
||||||
|
t.Errorf("in.ReadOptionalASN1OctetString() = %v, want %v; present = %v want %v; out = %v, want %v", ok, test.ok, present, test.present, out, test.out)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultInt = -1
|
||||||
|
|
||||||
|
var optionalIntTestData = []readASN1Test{
|
||||||
|
{"empty", []byte{}, 0xa0, true, defaultInt},
|
||||||
|
{"invalid", []byte{0xa1, 3, 0x2, 2, 127}, 0xa1, false, 0},
|
||||||
|
{"missing", []byte{0xa1, 3, 0x2, 1, 127}, 0xa0, true, defaultInt},
|
||||||
|
{"present", []byte{0xa1, 3, 0x2, 1, 42}, 0xa1, true, 42},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1OptionalInteger(t *testing.T) {
|
||||||
|
for _, test := range optionalIntTestData {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
in := String(test.in)
|
||||||
|
var out int
|
||||||
|
ok := in.ReadOptionalASN1Integer(&out, test.tag, defaultInt)
|
||||||
|
if ok != test.ok || ok && out != test.out.(int) {
|
||||||
|
t.Errorf("in.ReadOptionalASN1Integer() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1IntegerSigned(t *testing.T) {
|
||||||
|
testData64 := []struct {
|
||||||
|
in []byte
|
||||||
|
out int64
|
||||||
|
}{
|
||||||
|
{[]byte{2, 3, 128, 0, 0}, -0x800000},
|
||||||
|
{[]byte{2, 2, 255, 0}, -256},
|
||||||
|
{[]byte{2, 2, 255, 127}, -129},
|
||||||
|
{[]byte{2, 1, 128}, -128},
|
||||||
|
{[]byte{2, 1, 255}, -1},
|
||||||
|
{[]byte{2, 1, 0}, 0},
|
||||||
|
{[]byte{2, 1, 1}, 1},
|
||||||
|
{[]byte{2, 1, 2}, 2},
|
||||||
|
{[]byte{2, 1, 127}, 127},
|
||||||
|
{[]byte{2, 2, 0, 128}, 128},
|
||||||
|
{[]byte{2, 2, 1, 0}, 256},
|
||||||
|
{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
|
||||||
|
}
|
||||||
|
for i, test := range testData64 {
|
||||||
|
in := String(test.in)
|
||||||
|
var out int64
|
||||||
|
ok := in.ReadASN1Integer(&out)
|
||||||
|
if !ok || out != test.out {
|
||||||
|
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeat the same cases, reading into a big.Int.
|
||||||
|
t.Run("big.Int", func(t *testing.T) {
|
||||||
|
for i, test := range testData64 {
|
||||||
|
in := String(test.in)
|
||||||
|
var out big.Int
|
||||||
|
ok := in.ReadASN1Integer(&out)
|
||||||
|
if !ok || out.Int64() != test.out {
|
||||||
|
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out.Int64(), test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1IntegerUnsigned(t *testing.T) {
|
||||||
|
testData := []struct {
|
||||||
|
in []byte
|
||||||
|
out uint64
|
||||||
|
}{
|
||||||
|
{[]byte{2, 1, 0}, 0},
|
||||||
|
{[]byte{2, 1, 1}, 1},
|
||||||
|
{[]byte{2, 1, 2}, 2},
|
||||||
|
{[]byte{2, 1, 127}, 127},
|
||||||
|
{[]byte{2, 2, 0, 128}, 128},
|
||||||
|
{[]byte{2, 2, 1, 0}, 256},
|
||||||
|
{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
|
||||||
|
{[]byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}, 0x7fffffffffffffff},
|
||||||
|
{[]byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}, 0x8000000000000000},
|
||||||
|
{[]byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}, 0xffffffffffffffff},
|
||||||
|
}
|
||||||
|
for i, test := range testData {
|
||||||
|
in := String(test.in)
|
||||||
|
var out uint64
|
||||||
|
ok := in.ReadASN1Integer(&out)
|
||||||
|
if !ok || out != test.out {
|
||||||
|
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1IntegerInvalid(t *testing.T) {
|
||||||
|
testData := []String{
|
||||||
|
[]byte{3, 1, 0}, // invalid tag
|
||||||
|
// truncated
|
||||||
|
[]byte{2, 1},
|
||||||
|
[]byte{2, 2, 0},
|
||||||
|
// not minimally encoded
|
||||||
|
[]byte{2, 2, 0, 1},
|
||||||
|
[]byte{2, 2, 0xff, 0xff},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range testData {
|
||||||
|
var out int64
|
||||||
|
if test.ReadASN1Integer(&out) {
|
||||||
|
t.Errorf("#%d: in.ReadASN1Integer() = true, want false (out = %d)", i, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1ObjectIdentifier(t *testing.T) {
|
||||||
|
testData := []struct {
|
||||||
|
in []byte
|
||||||
|
ok bool
|
||||||
|
out []int
|
||||||
|
}{
|
||||||
|
{[]byte{}, false, []int{}},
|
||||||
|
{[]byte{6, 0}, false, []int{}},
|
||||||
|
{[]byte{5, 1, 85}, false, []int{2, 5}},
|
||||||
|
{[]byte{6, 1, 85}, true, []int{2, 5}},
|
||||||
|
{[]byte{6, 2, 85, 0x02}, true, []int{2, 5, 2}},
|
||||||
|
{[]byte{6, 4, 85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
|
||||||
|
{[]byte{6, 3, 0x81, 0x34, 0x03}, true, []int{2, 100, 3}},
|
||||||
|
{[]byte{6, 7, 85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range testData {
|
||||||
|
in := String(test.in)
|
||||||
|
var out asn1.ObjectIdentifier
|
||||||
|
ok := in.ReadASN1ObjectIdentifier(&out)
|
||||||
|
if ok != test.ok || ok && !out.Equal(test.out) {
|
||||||
|
t.Errorf("#%d: in.ReadASN1ObjectIdentifier() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1GeneralizedTime(t *testing.T) {
|
||||||
|
testData := []struct {
|
||||||
|
in string
|
||||||
|
ok bool
|
||||||
|
out time.Time
|
||||||
|
}{
|
||||||
|
{"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
|
||||||
|
{"20100102030405", false, time.Time{}},
|
||||||
|
{"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
|
||||||
|
{"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
|
||||||
|
/* These are invalid times. However, the time package normalises times
|
||||||
|
* and they were accepted in some versions. See #11134. */
|
||||||
|
{"00000100000000Z", false, time.Time{}},
|
||||||
|
{"20101302030405Z", false, time.Time{}},
|
||||||
|
{"20100002030405Z", false, time.Time{}},
|
||||||
|
{"20100100030405Z", false, time.Time{}},
|
||||||
|
{"20100132030405Z", false, time.Time{}},
|
||||||
|
{"20100231030405Z", false, time.Time{}},
|
||||||
|
{"20100102240405Z", false, time.Time{}},
|
||||||
|
{"20100102036005Z", false, time.Time{}},
|
||||||
|
{"20100102030460Z", false, time.Time{}},
|
||||||
|
{"-20100102030410Z", false, time.Time{}},
|
||||||
|
{"2010-0102030410Z", false, time.Time{}},
|
||||||
|
{"2010-0002030410Z", false, time.Time{}},
|
||||||
|
{"201001-02030410Z", false, time.Time{}},
|
||||||
|
{"20100102-030410Z", false, time.Time{}},
|
||||||
|
{"2010010203-0410Z", false, time.Time{}},
|
||||||
|
{"201001020304-10Z", false, time.Time{}},
|
||||||
|
}
|
||||||
|
for i, test := range testData {
|
||||||
|
in := String(append([]byte{asn1.TagGeneralizedTime, byte(len(test.in))}, test.in...))
|
||||||
|
var out time.Time
|
||||||
|
ok := in.ReadASN1GeneralizedTime(&out)
|
||||||
|
if ok != test.ok || ok && !reflect.DeepEqual(out, test.out) {
|
||||||
|
t.Errorf("#%d: in.ReadASN1GeneralizedTime() = %v, want %v; out = %q, want %q", i, ok, test.ok, out, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadASN1BitString(t *testing.T) {
|
||||||
|
testData := []struct {
|
||||||
|
in []byte
|
||||||
|
ok bool
|
||||||
|
out asn1.BitString
|
||||||
|
}{
|
||||||
|
{[]byte{}, false, asn1.BitString{}},
|
||||||
|
{[]byte{0x00}, true, asn1.BitString{}},
|
||||||
|
{[]byte{0x07, 0x00}, true, asn1.BitString{Bytes: []byte{0}, BitLength: 1}},
|
||||||
|
{[]byte{0x07, 0x01}, false, asn1.BitString{}},
|
||||||
|
{[]byte{0x07, 0x40}, false, asn1.BitString{}},
|
||||||
|
{[]byte{0x08, 0x00}, false, asn1.BitString{}},
|
||||||
|
{[]byte{0xff}, false, asn1.BitString{}},
|
||||||
|
{[]byte{0xfe, 0x00}, false, asn1.BitString{}},
|
||||||
|
}
|
||||||
|
for i, test := range testData {
|
||||||
|
in := String(append([]byte{3, byte(len(test.in))}, test.in...))
|
||||||
|
var out asn1.BitString
|
||||||
|
ok := in.ReadASN1BitString(&out)
|
||||||
|
if ok != test.ok || ok && (!bytes.Equal(out.Bytes, test.out.Bytes) || out.BitLength != test.out.BitLength) {
|
||||||
|
t.Errorf("#%d: in.ReadASN1BitString() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
255
vendor/golang.org/x/crypto/cryptobyte/builder.go
generated
vendored
Normal file
255
vendor/golang.org/x/crypto/cryptobyte/builder.go
generated
vendored
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cryptobyte
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Builder builds byte strings from fixed-length and length-prefixed values.
|
||||||
|
// The zero value is a usable Builder that allocates space as needed.
|
||||||
|
type Builder struct {
|
||||||
|
err error
|
||||||
|
result []byte
|
||||||
|
fixedSize bool
|
||||||
|
child *Builder
|
||||||
|
offset int
|
||||||
|
pendingLenLen int
|
||||||
|
pendingIsASN1 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuilder creates a Builder that appends its output to the given buffer.
|
||||||
|
// Like append(), the slice will be reallocated if its capacity is exceeded.
|
||||||
|
// Use Bytes to get the final buffer.
|
||||||
|
func NewBuilder(buffer []byte) *Builder {
|
||||||
|
return &Builder{
|
||||||
|
result: buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFixedBuilder creates a Builder that appends its output into the given
|
||||||
|
// buffer. This builder does not reallocate the output buffer. Writes that
|
||||||
|
// would exceed the buffer's capacity are treated as an error.
|
||||||
|
func NewFixedBuilder(buffer []byte) *Builder {
|
||||||
|
return &Builder{
|
||||||
|
result: buffer,
|
||||||
|
fixedSize: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the bytes written by the builder or an error if one has
|
||||||
|
// occurred during during building.
|
||||||
|
func (b *Builder) Bytes() ([]byte, error) {
|
||||||
|
if b.err != nil {
|
||||||
|
return nil, b.err
|
||||||
|
}
|
||||||
|
return b.result[b.offset:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesOrPanic returns the bytes written by the builder or panics if an error
|
||||||
|
// has occurred during building.
|
||||||
|
func (b *Builder) BytesOrPanic() []byte {
|
||||||
|
if b.err != nil {
|
||||||
|
panic(b.err)
|
||||||
|
}
|
||||||
|
return b.result[b.offset:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUint8 appends an 8-bit value to the byte string.
|
||||||
|
func (b *Builder) AddUint8(v uint8) {
|
||||||
|
b.add(byte(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUint16 appends a big-endian, 16-bit value to the byte string.
|
||||||
|
func (b *Builder) AddUint16(v uint16) {
|
||||||
|
b.add(byte(v>>8), byte(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
|
||||||
|
// byte of the 32-bit input value is silently truncated.
|
||||||
|
func (b *Builder) AddUint24(v uint32) {
|
||||||
|
b.add(byte(v>>16), byte(v>>8), byte(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUint32 appends a big-endian, 32-bit value to the byte string.
|
||||||
|
func (b *Builder) AddUint32(v uint32) {
|
||||||
|
b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddBytes appends a sequence of bytes to the byte string.
|
||||||
|
func (b *Builder) AddBytes(v []byte) {
|
||||||
|
b.add(v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuilderContinuation is 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
|
||||||
|
// to build the content of the length-prefixed sequence. Example:
|
||||||
|
//
|
||||||
|
// parent := cryptobyte.NewBuilder()
|
||||||
|
// parent.AddUint8LengthPrefixed(func (child *Builder) {
|
||||||
|
// child.AddUint8(42)
|
||||||
|
// child.AddUint8LengthPrefixed(func (grandchild *Builder) {
|
||||||
|
// grandchild.AddUint8(5)
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// It is an error to write more bytes to the child than allowed by the reserved
|
||||||
|
// length prefix. After the continuation returns, the child must be considered
|
||||||
|
// invalid, i.e. users must not store any copies or references of the child
|
||||||
|
// that outlive the continuation.
|
||||||
|
type BuilderContinuation func(child *Builder)
|
||||||
|
|
||||||
|
// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
|
||||||
|
func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
|
||||||
|
b.addLengthPrefixed(1, false, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
|
||||||
|
func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
|
||||||
|
b.addLengthPrefixed(2, false, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
|
||||||
|
func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
|
||||||
|
b.addLengthPrefixed(3, false, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
|
||||||
|
// Subsequent writes can be ignored if the builder has encountered an error.
|
||||||
|
if b.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := len(b.result)
|
||||||
|
b.add(make([]byte, lenLen)...)
|
||||||
|
|
||||||
|
b.child = &Builder{
|
||||||
|
result: b.result,
|
||||||
|
fixedSize: b.fixedSize,
|
||||||
|
offset: offset,
|
||||||
|
pendingLenLen: lenLen,
|
||||||
|
pendingIsASN1: isASN1,
|
||||||
|
}
|
||||||
|
|
||||||
|
f(b.child)
|
||||||
|
b.flushChild()
|
||||||
|
if b.child != nil {
|
||||||
|
panic("cryptobyte: internal error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) flushChild() {
|
||||||
|
if b.child == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.child.flushChild()
|
||||||
|
child := b.child
|
||||||
|
b.child = nil
|
||||||
|
|
||||||
|
if child.err != nil {
|
||||||
|
b.err = child.err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
length := len(child.result) - child.pendingLenLen - child.offset
|
||||||
|
|
||||||
|
if length < 0 {
|
||||||
|
panic("cryptobyte: internal error") // result unexpectedly shrunk
|
||||||
|
}
|
||||||
|
|
||||||
|
if child.pendingIsASN1 {
|
||||||
|
// For ASN.1, we reserved a single byte for the length. If that turned out
|
||||||
|
// to be incorrect, we have to move the contents along in order to make
|
||||||
|
// space.
|
||||||
|
if child.pendingLenLen != 1 {
|
||||||
|
panic("cryptobyte: internal error")
|
||||||
|
}
|
||||||
|
var lenLen, lenByte uint8
|
||||||
|
if int64(length) > 0xfffffffe {
|
||||||
|
b.err = errors.New("pending ASN.1 child too long")
|
||||||
|
return
|
||||||
|
} else if length > 0xffffff {
|
||||||
|
lenLen = 5
|
||||||
|
lenByte = 0x80 | 4
|
||||||
|
} else if length > 0xffff {
|
||||||
|
lenLen = 4
|
||||||
|
lenByte = 0x80 | 3
|
||||||
|
} else if length > 0xff {
|
||||||
|
lenLen = 3
|
||||||
|
lenByte = 0x80 | 2
|
||||||
|
} else if length > 0x7f {
|
||||||
|
lenLen = 2
|
||||||
|
lenByte = 0x80 | 1
|
||||||
|
} else {
|
||||||
|
lenLen = 1
|
||||||
|
lenByte = uint8(length)
|
||||||
|
length = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the initial length byte, make space for successive length bytes,
|
||||||
|
// and adjust the offset.
|
||||||
|
child.result[child.offset] = lenByte
|
||||||
|
extraBytes := int(lenLen - 1)
|
||||||
|
if extraBytes != 0 {
|
||||||
|
child.add(make([]byte, extraBytes)...)
|
||||||
|
childStart := child.offset + child.pendingLenLen
|
||||||
|
copy(child.result[childStart+extraBytes:], child.result[childStart:])
|
||||||
|
}
|
||||||
|
child.offset++
|
||||||
|
child.pendingLenLen = extraBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
l := length
|
||||||
|
for i := child.pendingLenLen - 1; i >= 0; i-- {
|
||||||
|
child.result[child.offset+i] = uint8(l)
|
||||||
|
l >>= 8
|
||||||
|
}
|
||||||
|
if l != 0 {
|
||||||
|
b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !b.fixedSize {
|
||||||
|
b.result = child.result // In case child reallocated result.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) add(bytes ...byte) {
|
||||||
|
if b.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if b.child != nil {
|
||||||
|
panic("attempted write while child is pending")
|
||||||
|
}
|
||||||
|
if len(b.result)+len(bytes) < len(bytes) {
|
||||||
|
b.err = errors.New("cryptobyte: length overflow")
|
||||||
|
}
|
||||||
|
if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
|
||||||
|
b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.result = append(b.result, bytes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A MarshalingValue marshals itself into a Builder.
|
||||||
|
type MarshalingValue interface {
|
||||||
|
// Marshal is called by Builder.AddValue. It receives a pointer to a builder
|
||||||
|
// to marshal itself into. It may return an error that occurred during
|
||||||
|
// marshaling, such as unset or invalid values.
|
||||||
|
Marshal(b *Builder) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddValue calls Marshal on v, passing a pointer to the builder to append to.
|
||||||
|
// If Marshal returns an error, it is set on the Builder so that subsequent
|
||||||
|
// appends don't have an effect.
|
||||||
|
func (b *Builder) AddValue(v MarshalingValue) {
|
||||||
|
err := v.Marshal(b)
|
||||||
|
if err != nil {
|
||||||
|
b.err = err
|
||||||
|
}
|
||||||
|
}
|
379
vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go
generated
vendored
Normal file
379
vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go
generated
vendored
Normal file
|
@ -0,0 +1,379 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cryptobyte
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func builderBytesEq(b *Builder, want ...byte) error {
|
||||||
|
got := b.BytesOrPanic()
|
||||||
|
if !bytes.Equal(got, want) {
|
||||||
|
return fmt.Errorf("Bytes() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBytes(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
v := []byte("foobarbaz")
|
||||||
|
b.AddBytes(v[0:3])
|
||||||
|
b.AddBytes(v[3:4])
|
||||||
|
b.AddBytes(v[4:9])
|
||||||
|
if err := builderBytesEq(&b, v...); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
s := String(b.BytesOrPanic())
|
||||||
|
for _, w := range []string{"foo", "bar", "baz"} {
|
||||||
|
var got []byte
|
||||||
|
if !s.ReadBytes(&got, 3) {
|
||||||
|
t.Errorf("ReadBytes() = false, want true (w = %v)", w)
|
||||||
|
}
|
||||||
|
want := []byte(w)
|
||||||
|
if !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("ReadBytes(): got = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint8(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint8(42)
|
||||||
|
if err := builderBytesEq(&b, 42); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var s String = b.BytesOrPanic()
|
||||||
|
var v uint8
|
||||||
|
if !s.ReadUint8(&v) {
|
||||||
|
t.Error("ReadUint8() = false, want true")
|
||||||
|
}
|
||||||
|
if v != 42 {
|
||||||
|
t.Errorf("v = %d, want 42", v)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint16(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint16(65534)
|
||||||
|
if err := builderBytesEq(&b, 255, 254); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
var s String = b.BytesOrPanic()
|
||||||
|
var v uint16
|
||||||
|
if !s.ReadUint16(&v) {
|
||||||
|
t.Error("ReadUint16() == false, want true")
|
||||||
|
}
|
||||||
|
if v != 65534 {
|
||||||
|
t.Errorf("v = %d, want 65534", v)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint24(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint24(0xfffefd)
|
||||||
|
if err := builderBytesEq(&b, 255, 254, 253); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var s String = b.BytesOrPanic()
|
||||||
|
var v uint32
|
||||||
|
if !s.ReadUint24(&v) {
|
||||||
|
t.Error("ReadUint8() = false, want true")
|
||||||
|
}
|
||||||
|
if v != 0xfffefd {
|
||||||
|
t.Errorf("v = %d, want fffefd", v)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint24Truncation(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint24(0x10111213)
|
||||||
|
if err := builderBytesEq(&b, 0x11, 0x12, 0x13); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint32(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint32(0xfffefdfc)
|
||||||
|
if err := builderBytesEq(&b, 255, 254, 253, 252); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var s String = b.BytesOrPanic()
|
||||||
|
var v uint32
|
||||||
|
if !s.ReadUint32(&v) {
|
||||||
|
t.Error("ReadUint8() = false, want true")
|
||||||
|
}
|
||||||
|
if v != 0xfffefdfc {
|
||||||
|
t.Errorf("v = %x, want fffefdfc", v)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUMultiple(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint8(23)
|
||||||
|
b.AddUint32(0xfffefdfc)
|
||||||
|
b.AddUint16(42)
|
||||||
|
if err := builderBytesEq(&b, 23, 255, 254, 253, 252, 0, 42); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var s String = b.BytesOrPanic()
|
||||||
|
var (
|
||||||
|
x uint8
|
||||||
|
y uint32
|
||||||
|
z uint16
|
||||||
|
)
|
||||||
|
if !s.ReadUint8(&x) || !s.ReadUint32(&y) || !s.ReadUint16(&z) {
|
||||||
|
t.Error("ReadUint8() = false, want true")
|
||||||
|
}
|
||||||
|
if x != 23 || y != 0xfffefdfc || z != 42 {
|
||||||
|
t.Errorf("x, y, z = %d, %d, %d; want 23, 4294901244, 5", x, y, z)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint8LengthPrefixedSimple(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||||
|
c.AddUint8(23)
|
||||||
|
c.AddUint8(42)
|
||||||
|
})
|
||||||
|
if err := builderBytesEq(&b, 2, 23, 42); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var base, child String = b.BytesOrPanic(), nil
|
||||||
|
var x, y uint8
|
||||||
|
if !base.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) ||
|
||||||
|
!child.ReadUint8(&y) {
|
||||||
|
t.Error("parsing failed")
|
||||||
|
}
|
||||||
|
if x != 23 || y != 42 {
|
||||||
|
t.Errorf("want x, y == 23, 42; got %d, %d", x, y)
|
||||||
|
}
|
||||||
|
if len(base) != 0 {
|
||||||
|
t.Errorf("len(base) = %d, want 0", len(base))
|
||||||
|
}
|
||||||
|
if len(child) != 0 {
|
||||||
|
t.Errorf("len(child) = %d, want 0", len(child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint8LengthPrefixedMulti(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||||
|
c.AddUint8(23)
|
||||||
|
c.AddUint8(42)
|
||||||
|
})
|
||||||
|
b.AddUint8(5)
|
||||||
|
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||||
|
c.AddUint8(123)
|
||||||
|
c.AddUint8(234)
|
||||||
|
})
|
||||||
|
if err := builderBytesEq(&b, 2, 23, 42, 5, 2, 123, 234); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var s, child String = b.BytesOrPanic(), nil
|
||||||
|
var u, v, w, x, y uint8
|
||||||
|
if !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&u) || !child.ReadUint8(&v) ||
|
||||||
|
!s.ReadUint8(&w) || !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || !child.ReadUint8(&y) {
|
||||||
|
t.Error("parsing failed")
|
||||||
|
}
|
||||||
|
if u != 23 || v != 42 || w != 5 || x != 123 || y != 234 {
|
||||||
|
t.Errorf("u, v, w, x, y = %d, %d, %d, %d, %d; want 23, 42, 5, 123, 234",
|
||||||
|
u, v, w, x, y)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
if len(child) != 0 {
|
||||||
|
t.Errorf("len(child) = %d, want 0", len(child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUint8LengthPrefixedNested(t *testing.T) {
|
||||||
|
var b Builder
|
||||||
|
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||||
|
c.AddUint8(5)
|
||||||
|
c.AddUint8LengthPrefixed(func(d *Builder) {
|
||||||
|
d.AddUint8(23)
|
||||||
|
d.AddUint8(42)
|
||||||
|
})
|
||||||
|
c.AddUint8(123)
|
||||||
|
})
|
||||||
|
if err := builderBytesEq(&b, 5, 5, 2, 23, 42, 123); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var base, child1, child2 String = b.BytesOrPanic(), nil, nil
|
||||||
|
var u, v, w, x uint8
|
||||||
|
if !base.ReadUint8LengthPrefixed(&child1) {
|
||||||
|
t.Error("parsing base failed")
|
||||||
|
}
|
||||||
|
if !child1.ReadUint8(&u) || !child1.ReadUint8LengthPrefixed(&child2) || !child1.ReadUint8(&x) {
|
||||||
|
t.Error("parsing child1 failed")
|
||||||
|
}
|
||||||
|
if !child2.ReadUint8(&v) || !child2.ReadUint8(&w) {
|
||||||
|
t.Error("parsing child2 failed")
|
||||||
|
}
|
||||||
|
if u != 5 || v != 23 || w != 42 || x != 123 {
|
||||||
|
t.Errorf("u, v, w, x = %d, %d, %d, %d, want 5, 23, 42, 123",
|
||||||
|
u, v, w, x)
|
||||||
|
}
|
||||||
|
if len(base) != 0 {
|
||||||
|
t.Errorf("len(base) = %d, want 0", len(base))
|
||||||
|
}
|
||||||
|
if len(child1) != 0 {
|
||||||
|
t.Errorf("len(child1) = %d, want 0", len(child1))
|
||||||
|
}
|
||||||
|
if len(base) != 0 {
|
||||||
|
t.Errorf("len(child2) = %d, want 0", len(child2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreallocatedBuffer(t *testing.T) {
|
||||||
|
var buf [5]byte
|
||||||
|
b := NewBuilder(buf[0:0])
|
||||||
|
b.AddUint8(1)
|
||||||
|
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||||
|
c.AddUint8(3)
|
||||||
|
c.AddUint8(4)
|
||||||
|
})
|
||||||
|
b.AddUint16(1286) // Outgrow buf by one byte.
|
||||||
|
want := []byte{1, 2, 3, 4, 0}
|
||||||
|
if !bytes.Equal(buf[:], want) {
|
||||||
|
t.Errorf("buf = %v want %v", buf, want)
|
||||||
|
}
|
||||||
|
if err := builderBytesEq(b, 1, 2, 3, 4, 5, 6); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
c.AddUint8(2) // panics
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if recover() == nil {
|
||||||
|
t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
b.AddUint8(2) // panics
|
||||||
|
})
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if recover() == nil {
|
||||||
|
t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
b.AddUint8(2) // panics
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASN.1
|
||||||
|
|
||||||
|
func TestASN1Int64(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in int64
|
||||||
|
want []byte
|
||||||
|
}{
|
||||||
|
{-0x800000, []byte{2, 3, 128, 0, 0}},
|
||||||
|
{-256, []byte{2, 2, 255, 0}},
|
||||||
|
{-129, []byte{2, 2, 255, 127}},
|
||||||
|
{-128, []byte{2, 1, 128}},
|
||||||
|
{-1, []byte{2, 1, 255}},
|
||||||
|
{0, []byte{2, 1, 0}},
|
||||||
|
{1, []byte{2, 1, 1}},
|
||||||
|
{2, []byte{2, 1, 2}},
|
||||||
|
{127, []byte{2, 1, 127}},
|
||||||
|
{128, []byte{2, 2, 0, 128}},
|
||||||
|
{256, []byte{2, 2, 1, 0}},
|
||||||
|
{0x800000, []byte{2, 4, 0, 128, 0, 0}},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
var b Builder
|
||||||
|
b.AddASN1Int64(tt.in)
|
||||||
|
if err := builderBytesEq(&b, tt.want...); err != nil {
|
||||||
|
t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
|
||||||
|
}
|
||||||
|
|
||||||
|
var n int64
|
||||||
|
s := String(b.BytesOrPanic())
|
||||||
|
ok := s.ReadASN1Integer(&n)
|
||||||
|
if !ok || n != tt.in {
|
||||||
|
t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
|
||||||
|
ok, n, tt.in, i)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestASN1Uint64(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in uint64
|
||||||
|
want []byte
|
||||||
|
}{
|
||||||
|
{0, []byte{2, 1, 0}},
|
||||||
|
{1, []byte{2, 1, 1}},
|
||||||
|
{2, []byte{2, 1, 2}},
|
||||||
|
{127, []byte{2, 1, 127}},
|
||||||
|
{128, []byte{2, 2, 0, 128}},
|
||||||
|
{256, []byte{2, 2, 1, 0}},
|
||||||
|
{0x800000, []byte{2, 4, 0, 128, 0, 0}},
|
||||||
|
{0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}},
|
||||||
|
{0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}},
|
||||||
|
{0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}},
|
||||||
|
}
|
||||||
|
for i, tt := range tests {
|
||||||
|
var b Builder
|
||||||
|
b.AddASN1Uint64(tt.in)
|
||||||
|
if err := builderBytesEq(&b, tt.want...); err != nil {
|
||||||
|
t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
|
||||||
|
}
|
||||||
|
|
||||||
|
var n uint64
|
||||||
|
s := String(b.BytesOrPanic())
|
||||||
|
ok := s.ReadASN1Integer(&n)
|
||||||
|
if !ok || n != tt.in {
|
||||||
|
t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
|
||||||
|
ok, n, tt.in, i)
|
||||||
|
}
|
||||||
|
if len(s) != 0 {
|
||||||
|
t.Errorf("len(s) = %d, want 0", len(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
vendor/golang.org/x/crypto/cryptobyte/example_test.go
generated
vendored
Normal file
120
vendor/golang.org/x/crypto/cryptobyte/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cryptobyte_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/asn1"
|
||||||
|
"fmt"
|
||||||
|
"golang.org/x/crypto/cryptobyte"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleString_lengthPrefixed() {
|
||||||
|
// This is an example of parsing length-prefixed data (as found in, for
|
||||||
|
// example, TLS). Imagine a 16-bit prefixed series of 8-bit prefixed
|
||||||
|
// strings.
|
||||||
|
|
||||||
|
input := cryptobyte.String([]byte{0, 12, 5, 'h', 'e', 'l', 'l', 'o', 5, 'w', 'o', 'r', 'l', 'd'})
|
||||||
|
var result []string
|
||||||
|
|
||||||
|
var values cryptobyte.String
|
||||||
|
if !input.ReadUint16LengthPrefixed(&values) ||
|
||||||
|
!input.Empty() {
|
||||||
|
panic("bad format")
|
||||||
|
}
|
||||||
|
|
||||||
|
for !values.Empty() {
|
||||||
|
var value cryptobyte.String
|
||||||
|
if !values.ReadUint8LengthPrefixed(&value) {
|
||||||
|
panic("bad format")
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, string(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output: []string{"hello", "world"}
|
||||||
|
fmt.Printf("%#v\n", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleString_asn1() {
|
||||||
|
// This is an example of parsing ASN.1 data that looks like:
|
||||||
|
// Foo ::= SEQUENCE {
|
||||||
|
// version [6] INTEGER DEFAULT 0
|
||||||
|
// data OCTET STRING
|
||||||
|
// }
|
||||||
|
|
||||||
|
input := cryptobyte.String([]byte{0x30, 12, 0xa6, 3, 2, 1, 2, 4, 5, 'h', 'e', 'l', 'l', 'o'})
|
||||||
|
|
||||||
|
var (
|
||||||
|
version int64
|
||||||
|
data, inner, versionBytes cryptobyte.String
|
||||||
|
haveVersion bool
|
||||||
|
)
|
||||||
|
if !input.ReadASN1(&inner, cryptobyte.Tag(asn1.TagSequence).Constructed()) ||
|
||||||
|
!input.Empty() ||
|
||||||
|
!inner.ReadOptionalASN1(&versionBytes, &haveVersion, cryptobyte.Tag(6).Constructed().ContextSpecific()) ||
|
||||||
|
(haveVersion && !versionBytes.ReadASN1Integer(&version)) ||
|
||||||
|
(haveVersion && !versionBytes.Empty()) ||
|
||||||
|
!inner.ReadASN1(&data, asn1.TagOctetString) ||
|
||||||
|
!inner.Empty() {
|
||||||
|
panic("bad format")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output: haveVersion: true, version: 2, data: hello
|
||||||
|
fmt.Printf("haveVersion: %t, version: %d, data: %s\n", haveVersion, version, string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleBuilder_asn1() {
|
||||||
|
// This is an example of building ASN.1 data that looks like:
|
||||||
|
// Foo ::= SEQUENCE {
|
||||||
|
// version [6] INTEGER DEFAULT 0
|
||||||
|
// data OCTET STRING
|
||||||
|
// }
|
||||||
|
|
||||||
|
version := int64(2)
|
||||||
|
data := []byte("hello")
|
||||||
|
const defaultVersion = 0
|
||||||
|
|
||||||
|
var b cryptobyte.Builder
|
||||||
|
b.AddASN1(cryptobyte.Tag(asn1.TagSequence).Constructed(), func(b *cryptobyte.Builder) {
|
||||||
|
if version != defaultVersion {
|
||||||
|
b.AddASN1(cryptobyte.Tag(6).Constructed().ContextSpecific(), func(b *cryptobyte.Builder) {
|
||||||
|
b.AddASN1Int64(version)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
b.AddASN1OctetString(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
result, err := b.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output: 300ca603020102040568656c6c6f
|
||||||
|
fmt.Printf("%x\n", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleBuilder_lengthPrefixed() {
|
||||||
|
// This is an example of building length-prefixed data (as found in,
|
||||||
|
// for example, TLS). Imagine a 16-bit prefixed series of 8-bit
|
||||||
|
// prefixed strings.
|
||||||
|
input := []string{"hello", "world"}
|
||||||
|
|
||||||
|
var b cryptobyte.Builder
|
||||||
|
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||||
|
for _, value := range input {
|
||||||
|
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||||
|
b.AddBytes([]byte(value))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
result, err := b.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output: 000c0568656c6c6f05776f726c64
|
||||||
|
fmt.Printf("%x\n", result)
|
||||||
|
}
|
157
vendor/golang.org/x/crypto/cryptobyte/string.go
generated
vendored
Normal file
157
vendor/golang.org/x/crypto/cryptobyte/string.go
generated
vendored
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package cryptobyte implements building and parsing of byte strings for
|
||||||
|
// DER-encoded ASN.1 and TLS messages. See the examples for the Builder and
|
||||||
|
// String types to get started.
|
||||||
|
package cryptobyte // import "golang.org/x/crypto/cryptobyte"
|
||||||
|
|
||||||
|
// String represents a string of bytes. It provides methods for parsing
|
||||||
|
// fixed-length and length-prefixed values from it.
|
||||||
|
type String []byte
|
||||||
|
|
||||||
|
// read advances a String by n bytes and returns them. If less than n bytes
|
||||||
|
// remain, it returns nil.
|
||||||
|
func (s *String) read(n int) []byte {
|
||||||
|
if len(*s) < n {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v := (*s)[:n]
|
||||||
|
*s = (*s)[n:]
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip advances the String by n byte and reports whether it was successful.
|
||||||
|
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.
|
||||||
|
func (s *String) ReadUint8(out *uint8) bool {
|
||||||
|
v := s.read(1)
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = uint8(v[0])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
|
||||||
|
// It returns true on success and false on error.
|
||||||
|
func (s *String) ReadUint16(out *uint16) bool {
|
||||||
|
v := s.read(2)
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = uint16(v[0])<<8 | uint16(v[1])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
|
||||||
|
// It returns true on success and false on error.
|
||||||
|
func (s *String) ReadUint24(out *uint32) bool {
|
||||||
|
v := s.read(3)
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
|
||||||
|
// It returns true on success and false on error.
|
||||||
|
func (s *String) ReadUint32(out *uint32) bool {
|
||||||
|
v := s.read(4)
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *String) readUnsigned(out *uint32, length int) bool {
|
||||||
|
v := s.read(length)
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var result uint32
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
result <<= 8
|
||||||
|
result |= uint32(v[i])
|
||||||
|
}
|
||||||
|
*out = result
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
|
||||||
|
lenBytes := s.read(lenLen)
|
||||||
|
if lenBytes == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var length uint32
|
||||||
|
for _, b := range lenBytes {
|
||||||
|
length = length << 8
|
||||||
|
length = length | uint32(b)
|
||||||
|
}
|
||||||
|
if int(length) < 0 {
|
||||||
|
// This currently cannot overflow because we read uint24 at most, but check
|
||||||
|
// anyway in case that changes in the future.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
v := s.read(int(length))
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*outChild = v
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
func (s *String) ReadBytes(out *[]byte, n int) bool {
|
||||||
|
v := s.read(n)
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*out = v
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyBytes copies len(out) bytes into out and advances over them. It returns
|
||||||
|
// true on success and false on error.
|
||||||
|
func (s *String) CopyBytes(out []byte) bool {
|
||||||
|
n := len(out)
|
||||||
|
v := s.read(n)
|
||||||
|
if v == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return copy(out, v) == n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty reports whether the string does not contain any bytes.
|
||||||
|
func (s String) Empty() bool {
|
||||||
|
return len(s) == 0
|
||||||
|
}
|
8
vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
Normal file
8
vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright 2012 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.
|
||||||
|
|
||||||
|
// This code was translated into a form compatible with 6a from the public
|
||||||
|
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
|
||||||
|
|
||||||
|
#define REDMASK51 0x0007FFFFFFFFFFFF
|
4
vendor/golang.org/x/crypto/curve25519/const_amd64.s
generated
vendored
4
vendor/golang.org/x/crypto/curve25519/const_amd64.s
generated
vendored
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
// +build amd64,!gccgo,!appengine
|
||||||
|
|
||||||
DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF
|
// These constants cannot be encoded in non-MOVQ immediates.
|
||||||
GLOBL ·REDMASK51(SB), 8, $8
|
// We access them directly from memory instead.
|
||||||
|
|
||||||
DATA ·_121666_213(SB)/8, $996687872
|
DATA ·_121666_213(SB)/8, $996687872
|
||||||
GLOBL ·_121666_213(SB), 8, $8
|
GLOBL ·_121666_213(SB), 8, $8
|
||||||
|
|
131
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
generated
vendored
131
vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
generated
vendored
|
@ -2,87 +2,64 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// This code was translated into a form compatible with 6a from the public
|
|
||||||
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
|
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
// +build amd64,!gccgo,!appengine
|
||||||
|
|
||||||
// func cswap(inout *[5]uint64, v uint64)
|
// func cswap(inout *[4][5]uint64, v uint64)
|
||||||
TEXT ·cswap(SB),7,$0
|
TEXT ·cswap(SB),7,$0
|
||||||
MOVQ inout+0(FP),DI
|
MOVQ inout+0(FP),DI
|
||||||
MOVQ v+8(FP),SI
|
MOVQ v+8(FP),SI
|
||||||
|
|
||||||
CMPQ SI,$1
|
SUBQ $1, SI
|
||||||
MOVQ 0(DI),SI
|
NOTQ SI
|
||||||
MOVQ 80(DI),DX
|
MOVQ SI, X15
|
||||||
MOVQ 8(DI),CX
|
PSHUFD $0x44, X15, X15
|
||||||
MOVQ 88(DI),R8
|
|
||||||
MOVQ SI,R9
|
MOVOU 0(DI), X0
|
||||||
CMOVQEQ DX,SI
|
MOVOU 16(DI), X2
|
||||||
CMOVQEQ R9,DX
|
MOVOU 32(DI), X4
|
||||||
MOVQ CX,R9
|
MOVOU 48(DI), X6
|
||||||
CMOVQEQ R8,CX
|
MOVOU 64(DI), X8
|
||||||
CMOVQEQ R9,R8
|
MOVOU 80(DI), X1
|
||||||
MOVQ SI,0(DI)
|
MOVOU 96(DI), X3
|
||||||
MOVQ DX,80(DI)
|
MOVOU 112(DI), X5
|
||||||
MOVQ CX,8(DI)
|
MOVOU 128(DI), X7
|
||||||
MOVQ R8,88(DI)
|
MOVOU 144(DI), X9
|
||||||
MOVQ 16(DI),SI
|
|
||||||
MOVQ 96(DI),DX
|
MOVO X1, X10
|
||||||
MOVQ 24(DI),CX
|
MOVO X3, X11
|
||||||
MOVQ 104(DI),R8
|
MOVO X5, X12
|
||||||
MOVQ SI,R9
|
MOVO X7, X13
|
||||||
CMOVQEQ DX,SI
|
MOVO X9, X14
|
||||||
CMOVQEQ R9,DX
|
|
||||||
MOVQ CX,R9
|
PXOR X0, X10
|
||||||
CMOVQEQ R8,CX
|
PXOR X2, X11
|
||||||
CMOVQEQ R9,R8
|
PXOR X4, X12
|
||||||
MOVQ SI,16(DI)
|
PXOR X6, X13
|
||||||
MOVQ DX,96(DI)
|
PXOR X8, X14
|
||||||
MOVQ CX,24(DI)
|
PAND X15, X10
|
||||||
MOVQ R8,104(DI)
|
PAND X15, X11
|
||||||
MOVQ 32(DI),SI
|
PAND X15, X12
|
||||||
MOVQ 112(DI),DX
|
PAND X15, X13
|
||||||
MOVQ 40(DI),CX
|
PAND X15, X14
|
||||||
MOVQ 120(DI),R8
|
PXOR X10, X0
|
||||||
MOVQ SI,R9
|
PXOR X10, X1
|
||||||
CMOVQEQ DX,SI
|
PXOR X11, X2
|
||||||
CMOVQEQ R9,DX
|
PXOR X11, X3
|
||||||
MOVQ CX,R9
|
PXOR X12, X4
|
||||||
CMOVQEQ R8,CX
|
PXOR X12, X5
|
||||||
CMOVQEQ R9,R8
|
PXOR X13, X6
|
||||||
MOVQ SI,32(DI)
|
PXOR X13, X7
|
||||||
MOVQ DX,112(DI)
|
PXOR X14, X8
|
||||||
MOVQ CX,40(DI)
|
PXOR X14, X9
|
||||||
MOVQ R8,120(DI)
|
|
||||||
MOVQ 48(DI),SI
|
MOVOU X0, 0(DI)
|
||||||
MOVQ 128(DI),DX
|
MOVOU X2, 16(DI)
|
||||||
MOVQ 56(DI),CX
|
MOVOU X4, 32(DI)
|
||||||
MOVQ 136(DI),R8
|
MOVOU X6, 48(DI)
|
||||||
MOVQ SI,R9
|
MOVOU X8, 64(DI)
|
||||||
CMOVQEQ DX,SI
|
MOVOU X1, 80(DI)
|
||||||
CMOVQEQ R9,DX
|
MOVOU X3, 96(DI)
|
||||||
MOVQ CX,R9
|
MOVOU X5, 112(DI)
|
||||||
CMOVQEQ R8,CX
|
MOVOU X7, 128(DI)
|
||||||
CMOVQEQ R9,R8
|
MOVOU X9, 144(DI)
|
||||||
MOVQ SI,48(DI)
|
|
||||||
MOVQ DX,128(DI)
|
|
||||||
MOVQ CX,56(DI)
|
|
||||||
MOVQ R8,136(DI)
|
|
||||||
MOVQ 64(DI),SI
|
|
||||||
MOVQ 144(DI),DX
|
|
||||||
MOVQ 72(DI),CX
|
|
||||||
MOVQ 152(DI),R8
|
|
||||||
MOVQ SI,R9
|
|
||||||
CMOVQEQ DX,SI
|
|
||||||
CMOVQEQ R9,DX
|
|
||||||
MOVQ CX,R9
|
|
||||||
CMOVQEQ R8,CX
|
|
||||||
CMOVQEQ R9,R8
|
|
||||||
MOVQ SI,64(DI)
|
|
||||||
MOVQ DX,144(DI)
|
|
||||||
MOVQ CX,72(DI)
|
|
||||||
MOVQ R8,152(DI)
|
|
||||||
MOVQ DI,AX
|
|
||||||
MOVQ SI,DX
|
|
||||||
RET
|
RET
|
||||||
|
|
23
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
23
vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
|
@ -8,6 +8,10 @@
|
||||||
|
|
||||||
package curve25519
|
package curve25519
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
// This code is a port of the public domain, "ref10" implementation of
|
// This code is a port of the public domain, "ref10" implementation of
|
||||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
||||||
|
|
||||||
|
@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
|
||||||
//
|
//
|
||||||
// Preconditions: b in {0,1}.
|
// Preconditions: b in {0,1}.
|
||||||
func feCSwap(f, g *fieldElement, b int32) {
|
func feCSwap(f, g *fieldElement, b int32) {
|
||||||
var x fieldElement
|
|
||||||
b = -b
|
b = -b
|
||||||
for i := range x {
|
|
||||||
x[i] = b & (f[i] ^ g[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range f {
|
for i := range f {
|
||||||
f[i] ^= x[i]
|
t := b & (f[i] ^ g[i])
|
||||||
}
|
f[i] ^= t
|
||||||
for i := range g {
|
g[i] ^= t
|
||||||
g[i] ^= x[i]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +73,7 @@ func load3(in []byte) int64 {
|
||||||
|
|
||||||
// load4 reads a 32-bit, little-endian value from in.
|
// load4 reads a 32-bit, little-endian value from in.
|
||||||
func load4(in []byte) int64 {
|
func load4(in []byte) int64 {
|
||||||
var r int64
|
return int64(binary.LittleEndian.Uint32(in))
|
||||||
r = int64(in[0])
|
|
||||||
r |= int64(in[1]) << 8
|
|
||||||
r |= int64(in[2]) << 16
|
|
||||||
r |= int64(in[3]) << 24
|
|
||||||
return r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func feFromBytes(dst *fieldElement, src *[32]byte) {
|
func feFromBytes(dst *fieldElement, src *[32]byte) {
|
||||||
|
|
10
vendor/golang.org/x/crypto/curve25519/curve25519_test.go
generated
vendored
10
vendor/golang.org/x/crypto/curve25519/curve25519_test.go
generated
vendored
|
@ -27,3 +27,13 @@ func TestBaseScalarMult(t *testing.T) {
|
||||||
t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
|
t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkScalarBaseMult(b *testing.B) {
|
||||||
|
var in, out [32]byte
|
||||||
|
in[0] = 1
|
||||||
|
|
||||||
|
b.SetBytes(32)
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
ScalarBaseMult(&out, &in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
4
vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
generated
vendored
4
vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
generated
vendored
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
// +build amd64,!gccgo,!appengine
|
||||||
|
|
||||||
|
#include "const_amd64.h"
|
||||||
|
|
||||||
// func freeze(inout *[5]uint64)
|
// func freeze(inout *[5]uint64)
|
||||||
TEXT ·freeze(SB),7,$0-8
|
TEXT ·freeze(SB),7,$0-8
|
||||||
MOVQ inout+0(FP), DI
|
MOVQ inout+0(FP), DI
|
||||||
|
@ -16,7 +18,7 @@ TEXT ·freeze(SB),7,$0-8
|
||||||
MOVQ 16(DI),CX
|
MOVQ 16(DI),CX
|
||||||
MOVQ 24(DI),R8
|
MOVQ 24(DI),R8
|
||||||
MOVQ 32(DI),R9
|
MOVQ 32(DI),R9
|
||||||
MOVQ ·REDMASK51(SB),AX
|
MOVQ $REDMASK51,AX
|
||||||
MOVQ AX,R10
|
MOVQ AX,R10
|
||||||
SUBQ $18,R10
|
SUBQ $18,R10
|
||||||
MOVQ $3,R11
|
MOVQ $3,R11
|
||||||
|
|
20
vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
generated
vendored
20
vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
generated
vendored
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
// +build amd64,!gccgo,!appengine
|
||||||
|
|
||||||
|
#include "const_amd64.h"
|
||||||
|
|
||||||
// func ladderstep(inout *[5][5]uint64)
|
// func ladderstep(inout *[5][5]uint64)
|
||||||
TEXT ·ladderstep(SB),0,$296-8
|
TEXT ·ladderstep(SB),0,$296-8
|
||||||
MOVQ inout+0(FP),DI
|
MOVQ inout+0(FP),DI
|
||||||
|
@ -118,7 +120,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 72(SP)
|
MULQ 72(SP)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -233,7 +235,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 32(SP)
|
MULQ 32(SP)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -438,7 +440,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 72(SP)
|
MULQ 72(SP)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -588,7 +590,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 32(SP)
|
MULQ 32(SP)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -728,7 +730,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 152(DI)
|
MULQ 152(DI)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -843,7 +845,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 192(DI)
|
MULQ 192(DI)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -993,7 +995,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 32(DI)
|
MULQ 32(DI)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -1143,7 +1145,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 112(SP)
|
MULQ 112(SP)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
@ -1329,7 +1331,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||||
MULQ 192(SP)
|
MULQ 192(SP)
|
||||||
ADDQ AX,R12
|
ADDQ AX,R12
|
||||||
ADCQ DX,R13
|
ADCQ DX,R13
|
||||||
MOVQ ·REDMASK51(SB),DX
|
MOVQ $REDMASK51,DX
|
||||||
SHLQ $13,CX:SI
|
SHLQ $13,CX:SI
|
||||||
ANDQ DX,SI
|
ANDQ DX,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
|
|
4
vendor/golang.org/x/crypto/curve25519/mul_amd64.s
generated
vendored
4
vendor/golang.org/x/crypto/curve25519/mul_amd64.s
generated
vendored
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
// +build amd64,!gccgo,!appengine
|
||||||
|
|
||||||
|
#include "const_amd64.h"
|
||||||
|
|
||||||
// func mul(dest, a, b *[5]uint64)
|
// func mul(dest, a, b *[5]uint64)
|
||||||
TEXT ·mul(SB),0,$16-24
|
TEXT ·mul(SB),0,$16-24
|
||||||
MOVQ dest+0(FP), DI
|
MOVQ dest+0(FP), DI
|
||||||
|
@ -121,7 +123,7 @@ TEXT ·mul(SB),0,$16-24
|
||||||
MULQ 32(CX)
|
MULQ 32(CX)
|
||||||
ADDQ AX,R14
|
ADDQ AX,R14
|
||||||
ADCQ DX,R15
|
ADCQ DX,R15
|
||||||
MOVQ ·REDMASK51(SB),SI
|
MOVQ $REDMASK51,SI
|
||||||
SHLQ $13,R9:R8
|
SHLQ $13,R9:R8
|
||||||
ANDQ SI,R8
|
ANDQ SI,R8
|
||||||
SHLQ $13,R11:R10
|
SHLQ $13,R11:R10
|
||||||
|
|
4
vendor/golang.org/x/crypto/curve25519/square_amd64.s
generated
vendored
4
vendor/golang.org/x/crypto/curve25519/square_amd64.s
generated
vendored
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
// +build amd64,!gccgo,!appengine
|
// +build amd64,!gccgo,!appengine
|
||||||
|
|
||||||
|
#include "const_amd64.h"
|
||||||
|
|
||||||
// func square(out, in *[5]uint64)
|
// func square(out, in *[5]uint64)
|
||||||
TEXT ·square(SB),7,$0-16
|
TEXT ·square(SB),7,$0-16
|
||||||
MOVQ out+0(FP), DI
|
MOVQ out+0(FP), DI
|
||||||
|
@ -84,7 +86,7 @@ TEXT ·square(SB),7,$0-16
|
||||||
MULQ 32(SI)
|
MULQ 32(SI)
|
||||||
ADDQ AX,R13
|
ADDQ AX,R13
|
||||||
ADCQ DX,R14
|
ADCQ DX,R14
|
||||||
MOVQ ·REDMASK51(SB),SI
|
MOVQ $REDMASK51,SI
|
||||||
SHLQ $13,R8:CX
|
SHLQ $13,R8:CX
|
||||||
ANDQ SI,CX
|
ANDQ SI,CX
|
||||||
SHLQ $13,R10:R9
|
SHLQ $13,R10:R9
|
||||||
|
|
95
vendor/golang.org/x/crypto/nacl/box/example_test.go
generated
vendored
Normal file
95
vendor/golang.org/x/crypto/nacl/box/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package box_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
crypto_rand "crypto/rand" // Custom so it's clear which rand we're using.
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/nacl/box"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Example() {
|
||||||
|
senderPublicKey, senderPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recipientPublicKey, recipientPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// You must use a different nonce for each message you encrypt with the
|
||||||
|
// same key. Since the nonce here is 192 bits long, a random value
|
||||||
|
// provides a sufficiently small probability of repeats.
|
||||||
|
var nonce [24]byte
|
||||||
|
if _, err := io.ReadFull(crypto_rand.Reader, nonce[:]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := []byte("Alas, poor Yorick! I knew him, Horatio")
|
||||||
|
// This encrypts msg and appends the result to the nonce.
|
||||||
|
encrypted := box.Seal(nonce[:], msg, &nonce, recipientPublicKey, senderPrivateKey)
|
||||||
|
|
||||||
|
// The recipient can decrypt the message using their private key and the
|
||||||
|
// sender's public key. When you decrypt, you must use the same nonce you
|
||||||
|
// used to encrypt the message. One way to achieve this is to store the
|
||||||
|
// nonce alongside the encrypted message. Above, we stored the nonce in the
|
||||||
|
// first 24 bytes of the encrypted text.
|
||||||
|
var decryptNonce [24]byte
|
||||||
|
copy(decryptNonce[:], encrypted[:24])
|
||||||
|
decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
|
||||||
|
if !ok {
|
||||||
|
panic("decryption error")
|
||||||
|
}
|
||||||
|
fmt.Println(string(decrypted))
|
||||||
|
// Output: Alas, poor Yorick! I knew him, Horatio
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_precompute() {
|
||||||
|
senderPublicKey, senderPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recipientPublicKey, recipientPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The shared key can be used to speed up processing when using the same
|
||||||
|
// pair of keys repeatedly.
|
||||||
|
sharedEncryptKey := new([32]byte)
|
||||||
|
box.Precompute(sharedEncryptKey, recipientPublicKey, senderPrivateKey)
|
||||||
|
|
||||||
|
// You must use a different nonce for each message you encrypt with the
|
||||||
|
// same key. Since the nonce here is 192 bits long, a random value
|
||||||
|
// provides a sufficiently small probability of repeats.
|
||||||
|
var nonce [24]byte
|
||||||
|
if _, err := io.ReadFull(crypto_rand.Reader, nonce[:]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := []byte("A fellow of infinite jest, of most excellent fancy")
|
||||||
|
// This encrypts msg and appends the result to the nonce.
|
||||||
|
encrypted := box.SealAfterPrecomputation(nonce[:], msg, &nonce, sharedEncryptKey)
|
||||||
|
|
||||||
|
// The shared key can be used to speed up processing when using the same
|
||||||
|
// pair of keys repeatedly.
|
||||||
|
var sharedDecryptKey [32]byte
|
||||||
|
box.Precompute(&sharedDecryptKey, senderPublicKey, recipientPrivateKey)
|
||||||
|
|
||||||
|
// The recipient can decrypt the message using the shared key. When you
|
||||||
|
// decrypt, you must use the same nonce you used to encrypt the message.
|
||||||
|
// One way to achieve this is to store the nonce alongside the encrypted
|
||||||
|
// message. Above, we stored the nonce in the first 24 bytes of the
|
||||||
|
// encrypted text.
|
||||||
|
var decryptNonce [24]byte
|
||||||
|
copy(decryptNonce[:], encrypted[:24])
|
||||||
|
decrypted, ok := box.OpenAfterPrecomputation(nil, encrypted[24:], &decryptNonce, &sharedDecryptKey)
|
||||||
|
if !ok {
|
||||||
|
panic("decryption error")
|
||||||
|
}
|
||||||
|
fmt.Println(string(decrypted))
|
||||||
|
// Output: A fellow of infinite jest, of most excellent fancy
|
||||||
|
}
|
2
vendor/golang.org/x/crypto/nacl/secretbox/example_test.go
generated
vendored
2
vendor/golang.org/x/crypto/nacl/secretbox/example_test.go
generated
vendored
|
@ -43,7 +43,7 @@ func Example() {
|
||||||
// 24 bytes of the encrypted text.
|
// 24 bytes of the encrypted text.
|
||||||
var decryptNonce [24]byte
|
var decryptNonce [24]byte
|
||||||
copy(decryptNonce[:], encrypted[:24])
|
copy(decryptNonce[:], encrypted[:24])
|
||||||
decrypted, ok := secretbox.Open([]byte{}, encrypted[24:], &decryptNonce, &secretKey)
|
decrypted, ok := secretbox.Open(nil, encrypted[24:], &decryptNonce, &secretKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("decryption error")
|
panic("decryption error")
|
||||||
}
|
}
|
||||||
|
|
63
vendor/golang.org/x/crypto/nacl/secretbox/secretbox_test.go
generated
vendored
63
vendor/golang.org/x/crypto/nacl/secretbox/secretbox_test.go
generated
vendored
|
@ -89,3 +89,66 @@ func TestAppend(t *testing.T) {
|
||||||
t.Fatalf("Seal didn't correctly append with sufficient capacity.")
|
t.Fatalf("Seal didn't correctly append with sufficient capacity.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func benchmarkSealSize(b *testing.B, size int) {
|
||||||
|
message := make([]byte, size)
|
||||||
|
out := make([]byte, size+Overhead)
|
||||||
|
var nonce [24]byte
|
||||||
|
var key [32]byte
|
||||||
|
|
||||||
|
b.SetBytes(int64(size))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
out = Seal(out[:0], message, &nonce, &key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeal8Bytes(b *testing.B) {
|
||||||
|
benchmarkSealSize(b, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeal100Bytes(b *testing.B) {
|
||||||
|
benchmarkSealSize(b, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeal1K(b *testing.B) {
|
||||||
|
benchmarkSealSize(b, 1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeal8K(b *testing.B) {
|
||||||
|
benchmarkSealSize(b, 8192)
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkOpenSize(b *testing.B, size int) {
|
||||||
|
msg := make([]byte, size)
|
||||||
|
result := make([]byte, size)
|
||||||
|
var nonce [24]byte
|
||||||
|
var key [32]byte
|
||||||
|
box := Seal(nil, msg, &nonce, &key)
|
||||||
|
|
||||||
|
b.SetBytes(int64(size))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, ok := Open(result[:0], box, &nonce, &key); !ok {
|
||||||
|
panic("Open failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkOpen8Bytes(b *testing.B) {
|
||||||
|
benchmarkOpenSize(b, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkOpen100Bytes(b *testing.B) {
|
||||||
|
benchmarkOpenSize(b, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkOpen1K(b *testing.B) {
|
||||||
|
benchmarkOpenSize(b, 1024)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkOpen8K(b *testing.B) {
|
||||||
|
benchmarkOpenSize(b, 8192)
|
||||||
|
}
|
||||||
|
|
57
vendor/golang.org/x/crypto/ocsp/ocsp.go
generated
vendored
57
vendor/golang.org/x/crypto/ocsp/ocsp.go
generated
vendored
|
@ -450,8 +450,8 @@ func ParseRequest(bytes []byte) (*Request, error) {
|
||||||
// then the signature over the response is checked. If issuer is not nil then
|
// then the signature over the response is checked. If issuer is not nil then
|
||||||
// it will be used to validate the signature or embedded certificate.
|
// it will be used to validate the signature or embedded certificate.
|
||||||
//
|
//
|
||||||
// Invalid signatures or parse failures will result in a ParseError. Error
|
// Invalid responses and parse failures will result in a ParseError.
|
||||||
// responses will result in a ResponseError.
|
// Error responses will result in a ResponseError.
|
||||||
func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) {
|
func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) {
|
||||||
return ParseResponseForCert(bytes, nil, issuer)
|
return ParseResponseForCert(bytes, nil, issuer)
|
||||||
}
|
}
|
||||||
|
@ -462,8 +462,8 @@ func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) {
|
||||||
// issuer is not nil then it will be used to validate the signature or embedded
|
// issuer is not nil then it will be used to validate the signature or embedded
|
||||||
// certificate.
|
// certificate.
|
||||||
//
|
//
|
||||||
// Invalid signatures or parse failures will result in a ParseError. Error
|
// Invalid responses and parse failures will result in a ParseError.
|
||||||
// responses will result in a ResponseError.
|
// Error responses will result in a ResponseError.
|
||||||
func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Response, error) {
|
func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Response, error) {
|
||||||
var resp responseASN1
|
var resp responseASN1
|
||||||
rest, err := asn1.Unmarshal(bytes, &resp)
|
rest, err := asn1.Unmarshal(bytes, &resp)
|
||||||
|
@ -496,10 +496,32 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
|
||||||
return nil, ParseError("OCSP response contains bad number of responses")
|
return nil, ParseError("OCSP response contains bad number of responses")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var singleResp singleResponse
|
||||||
|
if cert == nil {
|
||||||
|
singleResp = basicResp.TBSResponseData.Responses[0]
|
||||||
|
} else {
|
||||||
|
match := false
|
||||||
|
for _, resp := range basicResp.TBSResponseData.Responses {
|
||||||
|
if cert == nil || cert.SerialNumber.Cmp(resp.CertID.SerialNumber) == 0 {
|
||||||
|
singleResp = resp
|
||||||
|
match = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
return nil, ParseError("no response matching the supplied certificate")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret := &Response{
|
ret := &Response{
|
||||||
TBSResponseData: basicResp.TBSResponseData.Raw,
|
TBSResponseData: basicResp.TBSResponseData.Raw,
|
||||||
Signature: basicResp.Signature.RightAlign(),
|
Signature: basicResp.Signature.RightAlign(),
|
||||||
SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm),
|
SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm),
|
||||||
|
Extensions: singleResp.SingleExtensions,
|
||||||
|
SerialNumber: singleResp.CertID.SerialNumber,
|
||||||
|
ProducedAt: basicResp.TBSResponseData.ProducedAt,
|
||||||
|
ThisUpdate: singleResp.ThisUpdate,
|
||||||
|
NextUpdate: singleResp.NextUpdate,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the ResponderID CHOICE tag. ResponderID can be flattened into
|
// Handle the ResponderID CHOICE tag. ResponderID can be flattened into
|
||||||
|
@ -542,25 +564,14 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r singleResponse
|
for _, ext := range singleResp.SingleExtensions {
|
||||||
for _, resp := range basicResp.TBSResponseData.Responses {
|
|
||||||
if cert == nil || cert.SerialNumber.Cmp(resp.CertID.SerialNumber) == 0 {
|
|
||||||
r = resp
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ext := range r.SingleExtensions {
|
|
||||||
if ext.Critical {
|
if ext.Critical {
|
||||||
return nil, ParseError("unsupported critical extension")
|
return nil, ParseError("unsupported critical extension")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.Extensions = r.SingleExtensions
|
|
||||||
|
|
||||||
ret.SerialNumber = r.CertID.SerialNumber
|
|
||||||
|
|
||||||
for h, oid := range hashOIDs {
|
for h, oid := range hashOIDs {
|
||||||
if r.CertID.HashAlgorithm.Algorithm.Equal(oid) {
|
if singleResp.CertID.HashAlgorithm.Algorithm.Equal(oid) {
|
||||||
ret.IssuerHash = h
|
ret.IssuerHash = h
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -570,20 +581,16 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case bool(r.Good):
|
case bool(singleResp.Good):
|
||||||
ret.Status = Good
|
ret.Status = Good
|
||||||
case bool(r.Unknown):
|
case bool(singleResp.Unknown):
|
||||||
ret.Status = Unknown
|
ret.Status = Unknown
|
||||||
default:
|
default:
|
||||||
ret.Status = Revoked
|
ret.Status = Revoked
|
||||||
ret.RevokedAt = r.Revoked.RevocationTime
|
ret.RevokedAt = singleResp.Revoked.RevocationTime
|
||||||
ret.RevocationReason = int(r.Revoked.Reason)
|
ret.RevocationReason = int(singleResp.Revoked.Reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
|
|
||||||
ret.ThisUpdate = r.ThisUpdate
|
|
||||||
ret.NextUpdate = r.NextUpdate
|
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
21
vendor/golang.org/x/crypto/ocsp/ocsp_test.go
generated
vendored
21
vendor/golang.org/x/crypto/ocsp/ocsp_test.go
generated
vendored
|
@ -225,7 +225,6 @@ func TestOCSPResponse(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
producedAt := time.Now().Truncate(time.Minute)
|
|
||||||
thisUpdate := time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC)
|
thisUpdate := time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC)
|
||||||
nextUpdate := time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC)
|
nextUpdate := time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC)
|
||||||
template := Response{
|
template := Response{
|
||||||
|
@ -284,8 +283,9 @@ func TestOCSPResponse(t *testing.T) {
|
||||||
t.Errorf("resp.Extensions: got %v, want %v", resp.Extensions, template.ExtraExtensions)
|
t.Errorf("resp.Extensions: got %v, want %v", resp.Extensions, template.ExtraExtensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !resp.ProducedAt.Equal(producedAt) {
|
delay := time.Since(resp.ProducedAt)
|
||||||
t.Errorf("resp.ProducedAt: got %d, want %d", resp.ProducedAt, producedAt)
|
if delay < -time.Hour || delay > time.Hour {
|
||||||
|
t.Errorf("resp.ProducedAt: got %s, want close to current time (%s)", resp.ProducedAt, time.Now())
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Status != template.Status {
|
if resp.Status != template.Status {
|
||||||
|
@ -343,6 +343,21 @@ func TestOCSPDecodeMultiResponse(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOCSPDecodeMultiResponseWithoutMatchingCert(t *testing.T) {
|
||||||
|
wrongCert, _ := hex.DecodeString(startComHex)
|
||||||
|
cert, err := x509.ParseCertificate(wrongCert)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
responseBytes, _ := hex.DecodeString(ocspMultiResponseHex)
|
||||||
|
_, err = ParseResponseForCert(responseBytes, cert, nil)
|
||||||
|
want := ParseError("no response matching the supplied certificate")
|
||||||
|
if err != want {
|
||||||
|
t.Errorf("err: got %q, want %q", err, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This OCSP response was taken from Thawte's public OCSP responder.
|
// This OCSP response was taken from Thawte's public OCSP responder.
|
||||||
// To recreate:
|
// To recreate:
|
||||||
// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
|
// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
|
||||||
|
|
4
vendor/golang.org/x/crypto/pkcs12/pkcs12.go
generated
vendored
4
vendor/golang.org/x/crypto/pkcs12/pkcs12.go
generated
vendored
|
@ -109,6 +109,10 @@ func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
|
||||||
|
|
||||||
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
|
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
blocks := make([]*pem.Block, 0, len(bags))
|
blocks := make([]*pem.Block, 0, len(bags))
|
||||||
for _, bag := range bags {
|
for _, bag := range bags {
|
||||||
block, err := convertBag(&bag, encodedPassword)
|
block, err := convertBag(&bag, encodedPassword)
|
||||||
|
|
67
vendor/golang.org/x/crypto/poly1305/poly1305_test.go
generated
vendored
67
vendor/golang.org/x/crypto/poly1305/poly1305_test.go
generated
vendored
|
@ -6,10 +6,14 @@ package poly1305
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"flag"
|
||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var stressFlag = flag.Bool("stress", false, "run slow stress tests")
|
||||||
|
|
||||||
var testData = []struct {
|
var testData = []struct {
|
||||||
in, k, correct []byte
|
in, k, correct []byte
|
||||||
}{
|
}{
|
||||||
|
@ -39,6 +43,36 @@ var testData = []struct {
|
||||||
[]byte{0x3b, 0x3a, 0x29, 0xe9, 0x3b, 0x21, 0x3a, 0x5c, 0x5c, 0x3b, 0x3b, 0x05, 0x3a, 0x3a, 0x8c, 0x0d},
|
[]byte{0x3b, 0x3a, 0x29, 0xe9, 0x3b, 0x21, 0x3a, 0x5c, 0x5c, 0x3b, 0x3b, 0x05, 0x3a, 0x3a, 0x8c, 0x0d},
|
||||||
[]byte{0x6d, 0xc1, 0x8b, 0x8c, 0x34, 0x4c, 0xd7, 0x99, 0x27, 0x11, 0x8b, 0xbe, 0x84, 0xb7, 0xf3, 0x14},
|
[]byte{0x6d, 0xc1, 0x8b, 0x8c, 0x34, 0x4c, 0xd7, 0x99, 0x27, 0x11, 0x8b, 0xbe, 0x84, 0xb7, 0xf3, 0x14},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// This test generates a result of (2^130-1) % (2^130-5).
|
||||||
|
[]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
[]byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// This test generates a result of (2^130-6) % (2^130-5).
|
||||||
|
[]byte{
|
||||||
|
0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
[]byte{0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// This test generates a result of (2^130-5) % (2^130-5).
|
||||||
|
[]byte{
|
||||||
|
0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
[]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
[]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSum(t *testing.T, unaligned bool) {
|
func testSum(t *testing.T, unaligned bool) {
|
||||||
|
@ -58,6 +92,39 @@ func testSum(t *testing.T, unaligned bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBurnin(t *testing.T) {
|
||||||
|
// This test can be used to sanity-check significant changes. It can
|
||||||
|
// take about many minutes to run, even on fast machines. It's disabled
|
||||||
|
// by default.
|
||||||
|
if !*stressFlag {
|
||||||
|
t.Skip("skipping without -stress")
|
||||||
|
}
|
||||||
|
|
||||||
|
var key [32]byte
|
||||||
|
var input [25]byte
|
||||||
|
var output [16]byte
|
||||||
|
|
||||||
|
for i := range key {
|
||||||
|
key[i] = 1
|
||||||
|
}
|
||||||
|
for i := range input {
|
||||||
|
input[i] = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint64(0); i < 1e10; i++ {
|
||||||
|
Sum(&output, input[:], &key)
|
||||||
|
copy(key[0:], output[:])
|
||||||
|
copy(key[16:], output[:])
|
||||||
|
copy(input[:], output[:])
|
||||||
|
copy(input[16:], output[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected = "5e3b866aea0b636d240c83c428f84bfa"
|
||||||
|
if got := hex.EncodeToString(output[:]); got != expected {
|
||||||
|
t.Errorf("expected %s, got %s", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSum(t *testing.T) { testSum(t, false) }
|
func TestSum(t *testing.T) { testSum(t, false) }
|
||||||
func TestSumUnaligned(t *testing.T) { testSum(t, true) }
|
func TestSumUnaligned(t *testing.T) { testSum(t, true) }
|
||||||
|
|
||||||
|
|
1614
vendor/golang.org/x/crypto/poly1305/sum_ref.go
generated
vendored
1614
vendor/golang.org/x/crypto/poly1305/sum_ref.go
generated
vendored
File diff suppressed because it is too large
Load diff
15
vendor/golang.org/x/crypto/ssh/agent/client_test.go
generated
vendored
15
vendor/golang.org/x/crypto/ssh/agent/client_test.go
generated
vendored
|
@ -182,7 +182,10 @@ func TestCert(t *testing.T) {
|
||||||
func netPipe() (net.Conn, net.Conn, error) {
|
func netPipe() (net.Conn, net.Conn, error) {
|
||||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
listener, err = net.Listen("tcp", "[::1]:0")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
c1, err := net.Dial("tcp", listener.Addr().String())
|
c1, err := net.Dial("tcp", listener.Addr().String())
|
||||||
|
@ -200,6 +203,9 @@ func netPipe() (net.Conn, net.Conn, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuth(t *testing.T) {
|
func TestAuth(t *testing.T) {
|
||||||
|
agent, _, cleanup := startAgent(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
a, b, err := netPipe()
|
a, b, err := netPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("netPipe: %v", err)
|
t.Fatalf("netPipe: %v", err)
|
||||||
|
@ -208,9 +214,6 @@ func TestAuth(t *testing.T) {
|
||||||
defer a.Close()
|
defer a.Close()
|
||||||
defer b.Close()
|
defer b.Close()
|
||||||
|
|
||||||
agent, _, cleanup := startAgent(t)
|
|
||||||
defer cleanup()
|
|
||||||
|
|
||||||
if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment"}); err != nil {
|
if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment"}); err != nil {
|
||||||
t.Errorf("Add: %v", err)
|
t.Errorf("Add: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -233,7 +236,9 @@ func TestAuth(t *testing.T) {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
conf := ssh.ClientConfig{}
|
conf := ssh.ClientConfig{
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers))
|
conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers))
|
||||||
conn, _, _, err := ssh.NewClientConn(b, "", &conf)
|
conn, _, _, err := ssh.NewClientConn(b, "", &conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
15
vendor/golang.org/x/crypto/ssh/agent/example_test.go
generated
vendored
15
vendor/golang.org/x/crypto/ssh/agent/example_test.go
generated
vendored
|
@ -6,20 +6,20 @@ package agent_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"golang.org/x/crypto/ssh/agent"
|
"golang.org/x/crypto/ssh/agent"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleClientAgent() {
|
func ExampleClientAgent() {
|
||||||
// ssh-agent has a UNIX socket under $SSH_AUTH_SOCK
|
// ssh-agent has a UNIX socket under $SSH_AUTH_SOCK
|
||||||
socket := os.Getenv("SSH_AUTH_SOCK")
|
socket := os.Getenv("SSH_AUTH_SOCK")
|
||||||
conn, err := net.Dial("unix", socket)
|
conn, err := net.Dial("unix", socket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("net.Dial: %v", err)
|
log.Fatalf("net.Dial: %v", err)
|
||||||
}
|
}
|
||||||
agentClient := agent.NewClient(conn)
|
agentClient := agent.NewClient(conn)
|
||||||
config := &ssh.ClientConfig{
|
config := &ssh.ClientConfig{
|
||||||
User: "username",
|
User: "username",
|
||||||
|
@ -29,6 +29,7 @@ func ExampleClientAgent() {
|
||||||
// wants it.
|
// wants it.
|
||||||
ssh.PublicKeysCallback(agentClient.Signers),
|
ssh.PublicKeysCallback(agentClient.Signers),
|
||||||
},
|
},
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
}
|
}
|
||||||
|
|
||||||
sshc, err := ssh.Dial("tcp", "localhost:22", config)
|
sshc, err := ssh.Dial("tcp", "localhost:22", config)
|
||||||
|
|
4
vendor/golang.org/x/crypto/ssh/agent/server_test.go
generated
vendored
4
vendor/golang.org/x/crypto/ssh/agent/server_test.go
generated
vendored
|
@ -56,7 +56,9 @@ func TestSetupForwardAgent(t *testing.T) {
|
||||||
incoming <- conn
|
incoming <- conn
|
||||||
}()
|
}()
|
||||||
|
|
||||||
conf := ssh.ClientConfig{}
|
conf := ssh.ClientConfig{
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
conn, chans, reqs, err := ssh.NewClientConn(b, "", &conf)
|
conn, chans, reqs, err := ssh.NewClientConn(b, "", &conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClientConn: %v", err)
|
t.Fatalf("NewClientConn: %v", err)
|
||||||
|
|
36
vendor/golang.org/x/crypto/ssh/certs.go
generated
vendored
36
vendor/golang.org/x/crypto/ssh/certs.go
generated
vendored
|
@ -251,10 +251,18 @@ type CertChecker struct {
|
||||||
// for user certificates.
|
// for user certificates.
|
||||||
SupportedCriticalOptions []string
|
SupportedCriticalOptions []string
|
||||||
|
|
||||||
// IsAuthority should return true if the key is recognized as
|
// IsUserAuthority should return true if the key is recognized as an
|
||||||
// an authority. This allows for certificates to be signed by other
|
// authority for the given user certificate. This allows for
|
||||||
// certificates.
|
// certificates to be signed by other certificates. This must be set
|
||||||
IsAuthority func(auth PublicKey) bool
|
// if this CertChecker will be checking user certificates.
|
||||||
|
IsUserAuthority func(auth PublicKey) bool
|
||||||
|
|
||||||
|
// IsHostAuthority should report whether the key is recognized as
|
||||||
|
// an authority for this host. This allows for certificates to be
|
||||||
|
// signed by other keys, and for those other keys to only be valid
|
||||||
|
// signers for particular hostnames. This must be set if this
|
||||||
|
// CertChecker will be checking host certificates.
|
||||||
|
IsHostAuthority func(auth PublicKey, address string) bool
|
||||||
|
|
||||||
// Clock is used for verifying time stamps. If nil, time.Now
|
// Clock is used for verifying time stamps. If nil, time.Now
|
||||||
// is used.
|
// is used.
|
||||||
|
@ -268,7 +276,7 @@ type CertChecker struct {
|
||||||
// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
|
// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
|
||||||
// public key that is not a certificate. It must implement host key
|
// public key that is not a certificate. It must implement host key
|
||||||
// validation or else, if nil, all such keys are rejected.
|
// validation or else, if nil, all such keys are rejected.
|
||||||
HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error
|
HostKeyFallback HostKeyCallback
|
||||||
|
|
||||||
// IsRevoked is called for each certificate so that revocation checking
|
// IsRevoked is called for each certificate so that revocation checking
|
||||||
// can be implemented. It should return true if the given certificate
|
// can be implemented. It should return true if the given certificate
|
||||||
|
@ -290,8 +298,17 @@ func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey)
|
||||||
if cert.CertType != HostCert {
|
if cert.CertType != HostCert {
|
||||||
return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
|
return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
|
||||||
}
|
}
|
||||||
|
if !c.IsHostAuthority(cert.SignatureKey, addr) {
|
||||||
|
return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
|
||||||
|
}
|
||||||
|
|
||||||
return c.CheckCert(addr, cert)
|
hostname, _, err := net.SplitHostPort(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass hostname only as principal for host certificates (consistent with OpenSSH)
|
||||||
|
return c.CheckCert(hostname, cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate checks a user certificate. Authenticate can be used as
|
// Authenticate checks a user certificate. Authenticate can be used as
|
||||||
|
@ -308,6 +325,9 @@ func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permis
|
||||||
if cert.CertType != UserCert {
|
if cert.CertType != UserCert {
|
||||||
return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
|
return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
|
||||||
}
|
}
|
||||||
|
if !c.IsUserAuthority(cert.SignatureKey) {
|
||||||
|
return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.CheckCert(conn.User(), cert); err != nil {
|
if err := c.CheckCert(conn.User(), cert); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -356,10 +376,6 @@ func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.IsAuthority(cert.SignatureKey) {
|
|
||||||
return fmt.Errorf("ssh: certificate signed by unrecognized authority")
|
|
||||||
}
|
|
||||||
|
|
||||||
clock := c.Clock
|
clock := c.Clock
|
||||||
if clock == nil {
|
if clock == nil {
|
||||||
clock = time.Now
|
clock = time.Now
|
||||||
|
|
30
vendor/golang.org/x/crypto/ssh/certs_test.go
generated
vendored
30
vendor/golang.org/x/crypto/ssh/certs_test.go
generated
vendored
|
@ -104,7 +104,7 @@ func TestValidateCert(t *testing.T) {
|
||||||
t.Fatalf("got %v (%T), want *Certificate", key, key)
|
t.Fatalf("got %v (%T), want *Certificate", key, key)
|
||||||
}
|
}
|
||||||
checker := CertChecker{}
|
checker := CertChecker{}
|
||||||
checker.IsAuthority = func(k PublicKey) bool {
|
checker.IsUserAuthority = func(k PublicKey) bool {
|
||||||
return bytes.Equal(k.Marshal(), validCert.SignatureKey.Marshal())
|
return bytes.Equal(k.Marshal(), validCert.SignatureKey.Marshal())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ func TestValidateCertTime(t *testing.T) {
|
||||||
checker := CertChecker{
|
checker := CertChecker{
|
||||||
Clock: func() time.Time { return time.Unix(ts, 0) },
|
Clock: func() time.Time { return time.Unix(ts, 0) },
|
||||||
}
|
}
|
||||||
checker.IsAuthority = func(k PublicKey) bool {
|
checker.IsUserAuthority = func(k PublicKey) bool {
|
||||||
return bytes.Equal(k.Marshal(),
|
return bytes.Equal(k.Marshal(),
|
||||||
testPublicKeys["ecdsa"].Marshal())
|
testPublicKeys["ecdsa"].Marshal())
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ func TestValidateCertTime(t *testing.T) {
|
||||||
|
|
||||||
func TestHostKeyCert(t *testing.T) {
|
func TestHostKeyCert(t *testing.T) {
|
||||||
cert := &Certificate{
|
cert := &Certificate{
|
||||||
ValidPrincipals: []string{"hostname", "hostname.domain"},
|
ValidPrincipals: []string{"hostname", "hostname.domain", "otherhost"},
|
||||||
Key: testPublicKeys["rsa"],
|
Key: testPublicKeys["rsa"],
|
||||||
ValidBefore: CertTimeInfinity,
|
ValidBefore: CertTimeInfinity,
|
||||||
CertType: HostCert,
|
CertType: HostCert,
|
||||||
|
@ -168,8 +168,8 @@ func TestHostKeyCert(t *testing.T) {
|
||||||
cert.SignCert(rand.Reader, testSigners["ecdsa"])
|
cert.SignCert(rand.Reader, testSigners["ecdsa"])
|
||||||
|
|
||||||
checker := &CertChecker{
|
checker := &CertChecker{
|
||||||
IsAuthority: func(p PublicKey) bool {
|
IsHostAuthority: func(p PublicKey, addr string) bool {
|
||||||
return bytes.Equal(testPublicKeys["ecdsa"].Marshal(), p.Marshal())
|
return addr == "hostname:22" && bytes.Equal(testPublicKeys["ecdsa"].Marshal(), p.Marshal())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,14 @@ func TestHostKeyCert(t *testing.T) {
|
||||||
t.Errorf("NewCertSigner: %v", err)
|
t.Errorf("NewCertSigner: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range []string{"hostname", "otherhost"} {
|
for _, test := range []struct {
|
||||||
|
addr string
|
||||||
|
succeed bool
|
||||||
|
}{
|
||||||
|
{addr: "hostname:22", succeed: true},
|
||||||
|
{addr: "otherhost:22", succeed: false}, // The certificate is valid for 'otherhost' as hostname, but we only recognize the authority of the signer for the address 'hostname:22'
|
||||||
|
{addr: "lasthost:22", succeed: false},
|
||||||
|
} {
|
||||||
c1, c2, err := netPipe()
|
c1, c2, err := netPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("netPipe: %v", err)
|
t.Fatalf("netPipe: %v", err)
|
||||||
|
@ -201,16 +208,15 @@ func TestHostKeyCert(t *testing.T) {
|
||||||
User: "user",
|
User: "user",
|
||||||
HostKeyCallback: checker.CheckHostKey,
|
HostKeyCallback: checker.CheckHostKey,
|
||||||
}
|
}
|
||||||
_, _, _, err = NewClientConn(c2, name, config)
|
_, _, _, err = NewClientConn(c2, test.addr, config)
|
||||||
|
|
||||||
succeed := name == "hostname"
|
if (err == nil) != test.succeed {
|
||||||
if (err == nil) != succeed {
|
t.Fatalf("NewClientConn(%q): %v", test.addr, err)
|
||||||
t.Fatalf("NewClientConn(%q): %v", name, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = <-errc
|
err = <-errc
|
||||||
if (err == nil) != succeed {
|
if (err == nil) != test.succeed {
|
||||||
t.Fatalf("NewServerConn(%q): %v", name, err)
|
t.Fatalf("NewServerConn(%q): %v", test.addr, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
vendor/golang.org/x/crypto/ssh/channel.go
generated
vendored
4
vendor/golang.org/x/crypto/ssh/channel.go
generated
vendored
|
@ -461,8 +461,8 @@ func (m *mux) newChannel(chanType string, direction channelDirection, extraData
|
||||||
pending: newBuffer(),
|
pending: newBuffer(),
|
||||||
extPending: newBuffer(),
|
extPending: newBuffer(),
|
||||||
direction: direction,
|
direction: direction,
|
||||||
incomingRequests: make(chan *Request, 16),
|
incomingRequests: make(chan *Request, chanSize),
|
||||||
msg: make(chan interface{}, 16),
|
msg: make(chan interface{}, chanSize),
|
||||||
chanType: chanType,
|
chanType: chanType,
|
||||||
extraData: extraData,
|
extraData: extraData,
|
||||||
mux: m,
|
mux: m,
|
||||||
|
|
64
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
64
vendor/golang.org/x/crypto/ssh/cipher.go
generated
vendored
|
@ -135,6 +135,7 @@ const prefixLen = 5
|
||||||
type streamPacketCipher struct {
|
type streamPacketCipher struct {
|
||||||
mac hash.Hash
|
mac hash.Hash
|
||||||
cipher cipher.Stream
|
cipher cipher.Stream
|
||||||
|
etm bool
|
||||||
|
|
||||||
// The following members are to avoid per-packet allocations.
|
// The following members are to avoid per-packet allocations.
|
||||||
prefix [prefixLen]byte
|
prefix [prefixLen]byte
|
||||||
|
@ -150,7 +151,14 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
var encryptedPaddingLength [1]byte
|
||||||
|
if s.mac != nil && s.etm {
|
||||||
|
copy(encryptedPaddingLength[:], s.prefix[4:5])
|
||||||
|
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
||||||
|
} else {
|
||||||
|
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
||||||
|
}
|
||||||
|
|
||||||
length := binary.BigEndian.Uint32(s.prefix[0:4])
|
length := binary.BigEndian.Uint32(s.prefix[0:4])
|
||||||
paddingLength := uint32(s.prefix[4])
|
paddingLength := uint32(s.prefix[4])
|
||||||
|
|
||||||
|
@ -159,7 +167,12 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
||||||
s.mac.Reset()
|
s.mac.Reset()
|
||||||
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
||||||
s.mac.Write(s.seqNumBytes[:])
|
s.mac.Write(s.seqNumBytes[:])
|
||||||
s.mac.Write(s.prefix[:])
|
if s.etm {
|
||||||
|
s.mac.Write(s.prefix[:4])
|
||||||
|
s.mac.Write(encryptedPaddingLength[:])
|
||||||
|
} else {
|
||||||
|
s.mac.Write(s.prefix[:])
|
||||||
|
}
|
||||||
macSize = uint32(s.mac.Size())
|
macSize = uint32(s.mac.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +197,17 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
||||||
}
|
}
|
||||||
mac := s.packetData[length-1:]
|
mac := s.packetData[length-1:]
|
||||||
data := s.packetData[:length-1]
|
data := s.packetData[:length-1]
|
||||||
|
|
||||||
|
if s.mac != nil && s.etm {
|
||||||
|
s.mac.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
s.cipher.XORKeyStream(data, data)
|
s.cipher.XORKeyStream(data, data)
|
||||||
|
|
||||||
if s.mac != nil {
|
if s.mac != nil {
|
||||||
s.mac.Write(data)
|
if !s.etm {
|
||||||
|
s.mac.Write(data)
|
||||||
|
}
|
||||||
s.macResult = s.mac.Sum(s.macResult[:0])
|
s.macResult = s.mac.Sum(s.macResult[:0])
|
||||||
if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
|
if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
|
||||||
return nil, errors.New("ssh: MAC failure")
|
return nil, errors.New("ssh: MAC failure")
|
||||||
|
@ -203,7 +223,13 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
|
||||||
return errors.New("ssh: packet too large")
|
return errors.New("ssh: packet too large")
|
||||||
}
|
}
|
||||||
|
|
||||||
paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple
|
aadlen := 0
|
||||||
|
if s.mac != nil && s.etm {
|
||||||
|
// packet length is not encrypted for EtM modes
|
||||||
|
aadlen = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
|
||||||
if paddingLength < 4 {
|
if paddingLength < 4 {
|
||||||
paddingLength += packetSizeMultiple
|
paddingLength += packetSizeMultiple
|
||||||
}
|
}
|
||||||
|
@ -220,15 +246,37 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
|
||||||
s.mac.Reset()
|
s.mac.Reset()
|
||||||
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
||||||
s.mac.Write(s.seqNumBytes[:])
|
s.mac.Write(s.seqNumBytes[:])
|
||||||
|
|
||||||
|
if s.etm {
|
||||||
|
// For EtM algorithms, the packet length must stay unencrypted,
|
||||||
|
// but the following data (padding length) must be encrypted
|
||||||
|
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
||||||
|
}
|
||||||
|
|
||||||
s.mac.Write(s.prefix[:])
|
s.mac.Write(s.prefix[:])
|
||||||
|
|
||||||
|
if !s.etm {
|
||||||
|
// For non-EtM algorithms, the algorithm is applied on unencrypted data
|
||||||
|
s.mac.Write(packet)
|
||||||
|
s.mac.Write(padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(s.mac != nil && s.etm) {
|
||||||
|
// For EtM algorithms, the padding length has already been encrypted
|
||||||
|
// and the packet length must remain unencrypted
|
||||||
|
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
s.cipher.XORKeyStream(packet, packet)
|
||||||
|
s.cipher.XORKeyStream(padding, padding)
|
||||||
|
|
||||||
|
if s.mac != nil && s.etm {
|
||||||
|
// For EtM algorithms, packet and padding must be encrypted
|
||||||
s.mac.Write(packet)
|
s.mac.Write(packet)
|
||||||
s.mac.Write(padding)
|
s.mac.Write(padding)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
|
||||||
s.cipher.XORKeyStream(packet, packet)
|
|
||||||
s.cipher.XORKeyStream(padding, padding)
|
|
||||||
|
|
||||||
if _, err := w.Write(s.prefix[:]); err != nil {
|
if _, err := w.Write(s.prefix[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
62
vendor/golang.org/x/crypto/ssh/cipher_test.go
generated
vendored
62
vendor/golang.org/x/crypto/ssh/cipher_test.go
generated
vendored
|
@ -26,39 +26,41 @@ func TestPacketCiphers(t *testing.T) {
|
||||||
defer delete(cipherModes, aes128cbcID)
|
defer delete(cipherModes, aes128cbcID)
|
||||||
|
|
||||||
for cipher := range cipherModes {
|
for cipher := range cipherModes {
|
||||||
kr := &kexResult{Hash: crypto.SHA1}
|
for mac := range macModes {
|
||||||
algs := directionAlgorithms{
|
kr := &kexResult{Hash: crypto.SHA1}
|
||||||
Cipher: cipher,
|
algs := directionAlgorithms{
|
||||||
MAC: "hmac-sha1",
|
Cipher: cipher,
|
||||||
Compression: "none",
|
MAC: mac,
|
||||||
}
|
Compression: "none",
|
||||||
client, err := newPacketCipher(clientKeys, algs, kr)
|
}
|
||||||
if err != nil {
|
client, err := newPacketCipher(clientKeys, algs, kr)
|
||||||
t.Errorf("newPacketCipher(client, %q): %v", cipher, err)
|
if err != nil {
|
||||||
continue
|
t.Errorf("newPacketCipher(client, %q, %q): %v", cipher, mac, err)
|
||||||
}
|
continue
|
||||||
server, err := newPacketCipher(clientKeys, algs, kr)
|
}
|
||||||
if err != nil {
|
server, err := newPacketCipher(clientKeys, algs, kr)
|
||||||
t.Errorf("newPacketCipher(client, %q): %v", cipher, err)
|
if err != nil {
|
||||||
continue
|
t.Errorf("newPacketCipher(client, %q, %q): %v", cipher, mac, err)
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
want := "bla bla"
|
want := "bla bla"
|
||||||
input := []byte(want)
|
input := []byte(want)
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
|
if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
|
||||||
t.Errorf("writePacket(%q): %v", cipher, err)
|
t.Errorf("writePacket(%q, %q): %v", cipher, mac, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
packet, err := server.readPacket(0, buf)
|
packet, err := server.readPacket(0, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("readPacket(%q): %v", cipher, err)
|
t.Errorf("readPacket(%q, %q): %v", cipher, mac, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if string(packet) != want {
|
if string(packet) != want {
|
||||||
t.Errorf("roundtrip(%q): got %q, want %q", cipher, packet, want)
|
t.Errorf("roundtrip(%q, %q): got %q, want %q", cipher, mac, packet, want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
58
vendor/golang.org/x/crypto/ssh/client.go
generated
vendored
58
vendor/golang.org/x/crypto/ssh/client.go
generated
vendored
|
@ -5,6 +5,7 @@
|
||||||
package ssh
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
@ -13,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client implements a traditional SSH client that supports shells,
|
// Client implements a traditional SSH client that supports shells,
|
||||||
// subprocesses, port forwarding and tunneled dialing.
|
// subprocesses, TCP port/streamlocal forwarding and tunneled dialing.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Conn
|
Conn
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = make(chan NewChannel, 16)
|
ch = make(chan NewChannel, chanSize)
|
||||||
c.channelHandlers[channelType] = ch
|
c.channelHandlers[channelType] = ch
|
||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
@ -59,6 +60,7 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
|
||||||
conn.forwards.closeAll()
|
conn.forwards.closeAll()
|
||||||
}()
|
}()
|
||||||
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
|
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
|
||||||
|
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +70,11 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
|
||||||
func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
|
func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
|
||||||
fullConf := *config
|
fullConf := *config
|
||||||
fullConf.SetDefaults()
|
fullConf.SetDefaults()
|
||||||
|
if fullConf.HostKeyCallback == nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback")
|
||||||
|
}
|
||||||
|
|
||||||
conn := &connection{
|
conn := &connection{
|
||||||
sshConn: sshConn{conn: c},
|
sshConn: sshConn{conn: c},
|
||||||
}
|
}
|
||||||
|
@ -173,6 +180,13 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) {
|
||||||
return NewClient(c, chans, reqs), nil
|
return NewClient(c, chans, reqs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HostKeyCallback is the function type used for verifying server
|
||||||
|
// keys. A HostKeyCallback must return nil if the host key is OK, or
|
||||||
|
// an error to reject it. It receives the hostname as passed to Dial
|
||||||
|
// or NewClientConn. The remote address is the RemoteAddr of the
|
||||||
|
// net.Conn underlying the the SSH connection.
|
||||||
|
type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
|
||||||
|
|
||||||
// A ClientConfig structure is used to configure a Client. It must not be
|
// A ClientConfig structure is used to configure a Client. It must not be
|
||||||
// modified after having been passed to an SSH function.
|
// modified after having been passed to an SSH function.
|
||||||
type ClientConfig struct {
|
type ClientConfig struct {
|
||||||
|
@ -188,10 +202,12 @@ type ClientConfig struct {
|
||||||
// be used during authentication.
|
// be used during authentication.
|
||||||
Auth []AuthMethod
|
Auth []AuthMethod
|
||||||
|
|
||||||
// HostKeyCallback, if not nil, is called during the cryptographic
|
// HostKeyCallback is called during the cryptographic
|
||||||
// handshake to validate the server's host key. A nil HostKeyCallback
|
// handshake to validate the server's host key. The client
|
||||||
// implies that all host keys are accepted.
|
// configuration must supply this callback for the connection
|
||||||
HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
|
// to succeed. The functions InsecureIgnoreHostKey or
|
||||||
|
// FixedHostKey can be used for simplistic host key checks.
|
||||||
|
HostKeyCallback HostKeyCallback
|
||||||
|
|
||||||
// ClientVersion contains the version identification string that will
|
// ClientVersion contains the version identification string that will
|
||||||
// be used for the connection. If empty, a reasonable default is used.
|
// be used for the connection. If empty, a reasonable default is used.
|
||||||
|
@ -209,3 +225,33 @@ type ClientConfig struct {
|
||||||
// A Timeout of zero means no timeout.
|
// A Timeout of zero means no timeout.
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsecureIgnoreHostKey returns a function that can be used for
|
||||||
|
// ClientConfig.HostKeyCallback to accept any host key. It should
|
||||||
|
// not be used for production code.
|
||||||
|
func InsecureIgnoreHostKey() HostKeyCallback {
|
||||||
|
return func(hostname string, remote net.Addr, key PublicKey) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fixedHostKey struct {
|
||||||
|
key PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error {
|
||||||
|
if f.key == nil {
|
||||||
|
return fmt.Errorf("ssh: required host key was nil")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(key.Marshal(), f.key.Marshal()) {
|
||||||
|
return fmt.Errorf("ssh: host key mismatch")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedHostKey returns a function for use in
|
||||||
|
// ClientConfig.HostKeyCallback to accept only a specific host key.
|
||||||
|
func FixedHostKey(key PublicKey) HostKeyCallback {
|
||||||
|
hk := &fixedHostKey{key}
|
||||||
|
return hk.check
|
||||||
|
}
|
||||||
|
|
49
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
49
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
|
@ -179,31 +179,26 @@ func (cb publicKeyCallback) method() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
|
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
|
||||||
// Authentication is performed in two stages. The first stage sends an
|
// Authentication is performed by sending an enquiry to test if a key is
|
||||||
// enquiry to test if each key is acceptable to the remote. The second
|
// acceptable to the remote. If the key is acceptable, the client will
|
||||||
// stage attempts to authenticate with the valid keys obtained in the
|
// attempt to authenticate with the valid key. If not the client will repeat
|
||||||
// first stage.
|
// the process with the remaining keys.
|
||||||
|
|
||||||
signers, err := cb()
|
signers, err := cb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
var validKeys []Signer
|
|
||||||
for _, signer := range signers {
|
|
||||||
if ok, err := validateKey(signer.PublicKey(), user, c); ok {
|
|
||||||
validKeys = append(validKeys, signer)
|
|
||||||
} else {
|
|
||||||
if err != nil {
|
|
||||||
return false, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// methods that may continue if this auth is not successful.
|
|
||||||
var methods []string
|
var methods []string
|
||||||
for _, signer := range validKeys {
|
for _, signer := range signers {
|
||||||
pub := signer.PublicKey()
|
ok, err := validateKey(signer.PublicKey(), user, c)
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pub := signer.PublicKey()
|
||||||
pubKey := pub.Marshal()
|
pubKey := pub.Marshal()
|
||||||
sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{
|
sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{
|
||||||
User: user,
|
User: user,
|
||||||
|
@ -236,13 +231,29 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
if success {
|
|
||||||
|
// If authentication succeeds or the list of available methods does not
|
||||||
|
// contain the "publickey" method, do not attempt to authenticate with any
|
||||||
|
// other keys. According to RFC 4252 Section 7, the latter can occur when
|
||||||
|
// additional authentication methods are required.
|
||||||
|
if success || !containsMethod(methods, cb.method()) {
|
||||||
return success, methods, err
|
return success, methods, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, methods, nil
|
return false, methods, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsMethod(methods []string, method string) bool {
|
||||||
|
for _, m := range methods {
|
||||||
|
if m == method {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// validateKey validates the key provided is acceptable to the server.
|
// validateKey validates the key provided is acceptable to the server.
|
||||||
func validateKey(key PublicKey, user string, c packetConn) (bool, error) {
|
func validateKey(key PublicKey, user string, c packetConn) (bool, error) {
|
||||||
pubKey := key.Marshal()
|
pubKey := key.Marshal()
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue