feat: cluster addons

This commit is contained in:
Mikaël Cluseau 2018-07-07 12:22:35 +11:00
parent 6c20c29106
commit 975f002935
78 changed files with 3226 additions and 123 deletions

26
addons.go Normal file
View File

@ -0,0 +1,26 @@
package main
// Kubernetes' compatible ConfigMap
type configMap struct {
APIVersion string `yaml:"apiVersion"` // v1
Kind string
Metadata metadata
Data map[string]string
}
type metadata struct {
Namespace string
Name string
}
func newConfigMap(name string) *configMap {
return &configMap{
APIVersion: "v1",
Kind: "ConfigMap",
Metadata: metadata{
Namespace: "kube-system",
Name: name,
},
Data: make(map[string]string),
}
}

21
go.mod
View File

@ -1,10 +1,25 @@
module novit.nc/direktil/local-server module novit.nc/direktil/local-server
require ( require (
cloud.google.com/go v0.24.0
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e
github.com/cloudflare/cfssl v0.0.0-20180530085446-275fb308ac70 github.com/cloudflare/cfssl v0.0.0-20180705210102-ff56ab5eb62a
github.com/go-sql-driver/mysql v1.4.0
github.com/golang/protobuf v1.1.0 github.com/golang/protobuf v1.1.0
github.com/google/certificate-transparency-go v1.0.19 github.com/google/certificate-transparency-go v1.0.20
github.com/googleapis/gax-go v1.0.0
github.com/kr/pretty v0.1.0
github.com/mattn/go-sqlite3 v1.9.0
golang.org/x/build v0.0.0-20180706045728-5a0b491d3d31
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8
golang.org/x/net v0.0.0-20180706051357-32a936f46389
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
novit.nc/direktil/pkg v0.0.0-20180619202319-3b512e61055e golang.org/x/tools v0.0.0-20180706162124-435878328fa3
google.golang.org/api v0.0.0-20180706000841-61180b1196c9
google.golang.org/appengine v1.1.0
google.golang.org/grpc v1.13.0
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
honnef.co/go/tools v0.0.0-20180628101929-85dde8b51d3a
novit.nc/direktil/pkg v0.0.0-20180707011528-e82b59c0324d
) )

80
http.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"encoding/json" "encoding/json"
"flag" "flag"
"log" "log"
@ -10,6 +11,7 @@ import (
"regexp" "regexp"
"strings" "strings"
yaml "gopkg.in/yaml.v2"
"novit.nc/direktil/pkg/clustersconfig" "novit.nc/direktil/pkg/clustersconfig"
) )
@ -193,3 +195,81 @@ func renderJSON(w http.ResponseWriter, v interface{}) {
w.Header().Add("Content-Type", "application/json") w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(v) json.NewEncoder(w).Encode(v)
} }
func serveClusters(w http.ResponseWriter, r *http.Request) {
cfg, err := readConfig()
if err != nil {
http.Error(w, "", http.StatusServiceUnavailable)
return
}
clusterNames := make([]string, len(cfg.Clusters))
for i, cluster := range cfg.Clusters {
clusterNames[i] = cluster.Name
}
renderJSON(w, clusterNames)
}
func serveCluster(w http.ResponseWriter, r *http.Request) {
// "/clusters/<name>/<what>" split => "", "clusters", "<name>", "<what>"
p := strings.Split(r.URL.Path, "/")
if len(p) != 4 {
http.NotFound(w, r)
return
}
clusterName, what := p[2], p[3]
cfg, err := readConfig()
if err != nil {
http.Error(w, "", http.StatusServiceUnavailable)
return
}
cluster := cfg.Cluster(clusterName)
if cluster == nil {
http.NotFound(w, r)
return
}
switch what {
case "addons":
if cluster.Addons == "" {
log.Printf("cluster %q has no addons defined", clusterName)
http.NotFound(w, r)
return
}
addons := cfg.Addons[cluster.Addons]
if addons == nil {
log.Printf("cluster %q: no addons with name %q", clusterName, cluster.Addons)
http.NotFound(w, r)
return
}
clusterAsMap := asMap(cluster)
cm := newConfigMap("cluster-addons")
for _, addon := range addons {
buf := &bytes.Buffer{}
err := addon.Execute(buf, clusterAsMap, nil)
if err != nil {
log.Printf("cluster %q: addons %q: failed to render %q: %v",
clusterName, cluster.Addons, addon.Name, err)
http.Error(w, "", http.StatusServiceUnavailable)
return
}
cm.Data[addon.Name] = buf.String()
}
yaml.NewEncoder(w).Encode(cm)
default:
http.NotFound(w, r)
}
}

View File

@ -42,6 +42,9 @@ func main() {
http.HandleFunc("/hosts", serveHosts) http.HandleFunc("/hosts", serveHosts)
http.HandleFunc("/hosts/", serveHost) http.HandleFunc("/hosts/", serveHost)
http.HandleFunc("/clusters", serveClusters)
http.HandleFunc("/clusters/", serveCluster)
if *address != "" { if *address != "" {
log.Print("HTTP listening on ", *address) log.Print("HTTP listening on ", *address)
go log.Fatal(http.ListenAndServe(*address, nil)) go log.Fatal(http.ListenAndServe(*address, nil))

View File

@ -30,15 +30,17 @@ type renderContext struct {
clusterConfig *clustersconfig.Config clusterConfig *clustersconfig.Config
} }
func newRenderContext(host *clustersconfig.Host, cfg *clustersconfig.Config) (*renderContext, error) { func newRenderContext(host *clustersconfig.Host, cfg *clustersconfig.Config) (ctx *renderContext, err error) {
cluster := cfg.Cluster(host.Cluster) cluster := cfg.Cluster(host.Cluster)
if cluster == nil { if cluster == nil {
return nil, fmt.Errorf("no cluster named %q", host.Cluster) err = fmt.Errorf("no cluster named %q", host.Cluster)
return
} }
group := cfg.Group(host.Group) group := cfg.Group(host.Group)
if group == nil { if group == nil {
return nil, fmt.Errorf("no group named %q", host.Group) err = fmt.Errorf("no group named %q", host.Group)
return
} }
vars := make(map[string]interface{}) vars := make(map[string]interface{})
@ -78,6 +80,20 @@ func (ctx *renderContext) Config() (ba []byte, cfg *config.Config, err error) {
return return
} }
templateFuncs := ctx.templateFuncs(secretData, ctxMap)
render := func(what string, t *clustersconfig.Template) (s string, err error) {
buf := &bytes.Buffer{}
err = t.Execute(buf, ctxMap, templateFuncs)
if err != nil {
log.Printf("host %s: failed to render %s [%q]: %v", ctx.Host.Name, what, t.Name, err)
return
}
s = buf.String()
return
}
extraFuncs := ctx.templateFuncs(secretData, ctxMap) extraFuncs := ctx.templateFuncs(secretData, ctxMap)
extraFuncs["static_pods"] = func(name string) (string, error) { extraFuncs["static_pods"] = func(name string) (string, error) {
@ -86,14 +102,7 @@ func (ctx *renderContext) Config() (ba []byte, cfg *config.Config, err error) {
return "", fmt.Errorf("no static pods template named %q", name) return "", fmt.Errorf("no static pods template named %q", name)
} }
buf := &bytes.Buffer{} return render("static pods", t)
err := t.Execute(buf, ctxMap, ctx.templateFuncs(secretData, ctxMap))
if err != nil {
log.Printf("host %s: failed to render static pods: %v", ctx.Host.Name, err)
return "", err
}
return buf.String(), nil
} }
buf := bytes.NewBuffer(make([]byte, 0, 4096)) buf := bytes.NewBuffer(make([]byte, 0, 4096))

View File

@ -17,6 +17,8 @@
/dumpscts /dumpscts
/etcdiscover /etcdiscover
/findlog /findlog
/goshawk
/gosmin
/gossip_server /gossip_server
/preloader /preloader
/scanlog /scanlog

View File

@ -1,7 +1,7 @@
sudo: true # required for CI push into Kubernetes. sudo: true # required for CI push into Kubernetes.
language: go language: go
os: linux os: linux
go: 1.9 go: "1.10"
go_import_path: github.com/google/certificate-transparency-go go_import_path: github.com/google/certificate-transparency-go
@ -22,8 +22,8 @@ install:
- | - |
( (
cd ../protoc cd ../protoc
wget https://github.com/google/protobuf/releases/download/v3.2.0/protoc-3.2.0-${TRAVIS_OS_NAME}-x86_64.zip wget https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-${TRAVIS_OS_NAME}-x86_64.zip
unzip protoc-3.2.0-${TRAVIS_OS_NAME}-x86_64.zip unzip protoc-3.5.1-${TRAVIS_OS_NAME}-x86_64.zip
) )
- export PATH=$(pwd)/../protoc/bin:$PATH - export PATH=$(pwd)/../protoc/bin:$PATH
- go get -d -t ./... - go get -d -t ./...

View File

@ -0,0 +1,194 @@
# CERTIFICATE-TRANSPARENCY-GO Changelog
## v1.0.19 - CTFE User Quota
Published 2018-06-01 13:51:52 +0000 UTC
CTFE now supports Trillian Log's explicit quota API; quota can be requested based on the remote user's IP, as well as per-issuing certificate in submitted chains.
Commit [8736a411b4ff214ea20687e46c2b67d66ebd83fc](https://api.github.com/repos/google/certificate-transparency-go/commits/8736a411b4ff214ea20687e46c2b67d66ebd83fc) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.19)
## v1.0.18 - Adding Migration Tool / Client Additions / K8 Config
Published 2018-06-01 14:28:20 +0000 UTC
Work on a log migration tool (Migrillian) is in progress. This is not yet ready for production use but will provide features for mirroring and migrating logs.
The `RequestLog` API allows for logging of SCTs when they are issued by CTFE.
The CT Go client now supports `GetEntryAndProof`. Utilities have been switched over to use the `glog` package.
Commit [77abf2dac5410a62c04ac1c662c6d0fa54afc2dc](https://api.github.com/repos/google/certificate-transparency-go/commits/77abf2dac5410a62c04ac1c662c6d0fa54afc2dc) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.18)
## v1.0.17 - Merkle verification / Tracing / Demo script / CORS
Published 2018-06-01 14:25:16 +0000 UTC
Now uses Merkle Tree verification from Trillian.
The CT server now supports CORS.
Request tracing added using OpenCensus. For GCE / K8 it just requires the flag to be enabled to export traces to Stackdriver. Other environments may differ.
A demo script was added that goes through setting up a simple deployment suitable for development / demo purposes. This may be useful for those new to the project.
Commit [3c3d22ce946447d047a03228ebb4a41e3e4eb15b](https://api.github.com/repos/google/certificate-transparency-go/commits/3c3d22ce946447d047a03228ebb4a41e3e4eb15b) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.17)
## v1.0.16 - Lifecycle test / Go 1.10.1
Published 2018-06-01 14:22:23 +0000 UTC
An integration test was added that goes through a create / drain queue / freeze lifecycle for a log.
Changes to `x509` were merged from Go 1.10.1.
Commit [a72423d09b410b80673fd1135ba1022d04bac6cd](https://api.github.com/repos/google/certificate-transparency-go/commits/a72423d09b410b80673fd1135ba1022d04bac6cd) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.16)
## v1.0.15 - More control of verification, grpclb, stackdriver metrics
Published 2018-06-01 14:20:32 +0000 UTC
Facilities were added to the `x509` package to control whether verification checks are applied.
Log server requests are now balanced using `gRPClb`.
For Kubernetes, metrics can be published to Stackdriver monitoring.
Commit [684d6eee6092774e54d301ccad0ed61bc8d010c1](https://api.github.com/repos/google/certificate-transparency-go/commits/684d6eee6092774e54d301ccad0ed61bc8d010c1) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.15)
## v1.0.14 - SQLite Removed, LeafHashForLeaf
Published 2018-06-01 14:15:37 +0000 UTC
Support for SQLlite was removed. This motivation was ongoing test flakiness caused by multi-user access. This database may work for an embedded scenario but is not suitable for use in a server environment.
A `LeafHashForLeaf` client API was added and is now used by the CT client and integration tests.
Commit [698cd6a661196db4b2e71437422178ffe8705006](https://api.github.com/repos/google/certificate-transparency-go/commits/698cd6a661196db4b2e71437422178ffe8705006) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.14)
## v1.0.13 - Crypto changes, util updates, sync with trillian repo, loglist verification
Published 2018-06-01 14:15:21 +0000 UTC
Some of our custom crypto package that were wrapping calls to the standard package have been removed and the base features used directly.
Updates were made to GCE ingress and health checks.
The log list utility can verify signatures.
Commit [480c3654a70c5383b9543ec784203030aedbd3a5](https://api.github.com/repos/google/certificate-transparency-go/commits/480c3654a70c5383b9543ec784203030aedbd3a5) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.13)
## v1.0.12 - Client / util updates & CTFE fixes
Published 2018-06-01 14:13:42 +0000 UTC
The CT client can now use a JSON loglist to find logs.
CTFE had a fix applied for preissued precerts.
A DNS client was added and CT client was extended to support DNS retrieval.
Commit [74c06c95e0b304a050a1c33764c8a01d653a16e3](https://api.github.com/repos/google/certificate-transparency-go/commits/74c06c95e0b304a050a1c33764c8a01d653a16e3) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.12)
## v1.0.11 - Kubernetes CI / Integration fixes
Published 2018-06-01 14:12:18 +0000 UTC
Updates to Kubernetes configs, mostly related to running a CI instance.
Commit [0856acca7e0ab7f082ae83a1fbb5d21160962efc](https://api.github.com/repos/google/certificate-transparency-go/commits/0856acca7e0ab7f082ae83a1fbb5d21160962efc) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.11)
## v1.0.10 - More scanner, x509, utility and client fixes. CTFE updates
Published 2018-06-01 14:09:47 +0000 UTC
The CT client was using the wrong protobuffer library package. To guard against this in future a check has been added to our lint config.
The `x509` and `asn1` packages have had upstream fixes applied from Go 1.10rc1.
Commit [1bec4527572c443752ad4f2830bef88be0533236](https://api.github.com/repos/google/certificate-transparency-go/commits/1bec4527572c443752ad4f2830bef88be0533236) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.10)
## v1.0.9 - Scanner, x509, utility and client fixes
Published 2018-06-01 14:11:13 +0000 UTC
The `scanner` utility now displays throughput stats.
Build instructions and README files were updated.
The `certcheck` utility can be told to ignore unknown critical X.509 extensions.
Commit [c06833528d04a94eed0c775104d1107bab9ae17c](https://api.github.com/repos/google/certificate-transparency-go/commits/c06833528d04a94eed0c775104d1107bab9ae17c) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.9)
## v1.0.8 - Client fixes, align with trillian repo
Published 2018-06-01 14:06:44 +0000 UTC
Commit [e8b02c60f294b503dbb67de0868143f5d4935e56](https://api.github.com/repos/google/certificate-transparency-go/commits/e8b02c60f294b503dbb67de0868143f5d4935e56) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.8)
## v1.0.7 - CTFE fixes
Published 2018-06-01 14:06:13 +0000 UTC
An issue was fixed with CTFE signature caching. In an unlikely set of circumstances this could lead to log mis-operation. While the chances of this are small, we recommend that versions prior to this one are not deployed.
Commit [52c0590bd3b4b80c5497005b0f47e10557425eeb](https://api.github.com/repos/google/certificate-transparency-go/commits/52c0590bd3b4b80c5497005b0f47e10557425eeb) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.7)
## v1.0.6 - crlcheck improvements / other fixes
Published 2018-06-01 14:04:22 +0000 UTC
The `crlcheck` utility has had several fixes and enhancements. Additionally the `hammer` now supports temporal logs.
Commit [3955e4a00c42e83ff17ce25003976159c5d0f0f9](https://api.github.com/repos/google/certificate-transparency-go/commits/3955e4a00c42e83ff17ce25003976159c5d0f0f9) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.6)
## v1.0.5 - X509 and asn1 fixes
Published 2018-06-01 14:02:58 +0000 UTC
This release is mostly fixes to the `x509` and `asn1` packages. Some command line utilties were also updated.
Commit [ae40d07cce12f1227c6e658e61c9dddb7646f97b](https://api.github.com/repos/google/certificate-transparency-go/commits/ae40d07cce12f1227c6e658e61c9dddb7646f97b) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.5)
## v1.0.4 - Multi log backend configs
Published 2018-06-01 14:02:07 +0000 UTC
Support was added to allow CTFE to use multiple backends, each serving a distinct set of logs. It allows for e.g. regional backend deployment with common frontend servers.
Commit [62023ed90b41fa40854957b5dec7d9d73594723f](https://api.github.com/repos/google/certificate-transparency-go/commits/62023ed90b41fa40854957b5dec7d9d73594723f) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.4)
## v1.0.3 - Hammer updates, use standard context
Published 2018-06-01 14:01:11 +0000 UTC
After the Go 1.9 migration references to anything other than the standard `context` package have been removed. This is the only one that should be used from now on.
Commit [b28beed8b9aceacc705e0ff4a11d435a310e3d97](https://api.github.com/repos/google/certificate-transparency-go/commits/b28beed8b9aceacc705e0ff4a11d435a310e3d97) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.3)
## v1.0.2 - Go 1.9
Published 2018-06-01 14:00:00 +0000 UTC
Go 1.9 is now required to build the code.
Commit [3aed33d672ee43f04b1e8a00b25ca3e2e2e74309](https://api.github.com/repos/google/certificate-transparency-go/commits/3aed33d672ee43f04b1e8a00b25ca3e2e2e74309) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.2)
## v1.0.1 - Hammer and client improvements
Published 2018-06-01 13:59:29 +0000 UTC
Commit [c28796cc21776667fb05d6300e32d9517be96515](https://api.github.com/repos/google/certificate-transparency-go/commits/c28796cc21776667fb05d6300e32d9517be96515) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.1)
## v1.0 - First Trillian CT Release
Published 2018-06-01 13:59:00 +0000 UTC
This is the point that corresponds to the 1.0 release in the trillian repo.
Commit [abb79e468b6f3bbd48d1ab0c9e68febf80d52c4d](https://api.github.com/repos/google/certificate-transparency-go/commits/abb79e468b6f3bbd48d1ab0c9e68febf80d52c4d) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0)

View File

@ -22,7 +22,7 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// TemporalLogConfig is a set of LogShardConfig messages, whose // TemporalLogConfig is a set of LogShardConfig messages, whose
// time limits should be contiguous. // time limits should be contiguous.
type TemporalLogConfig struct { type TemporalLogConfig struct {
Shard []*LogShardConfig `protobuf:"bytes,1,rep,name=shard" json:"shard,omitempty"` Shard []*LogShardConfig `protobuf:"bytes,1,rep,name=shard,proto3" json:"shard,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -62,17 +62,17 @@ func (m *TemporalLogConfig) GetShard() []*LogShardConfig {
// LogShardConfig describes the acceptable date range for a single shard of a temporal // LogShardConfig describes the acceptable date range for a single shard of a temporal
// log. // log.
type LogShardConfig struct { type LogShardConfig struct {
Uri string `protobuf:"bytes,1,opt,name=uri" json:"uri,omitempty"` Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"`
// The log's public key in DER-encoded PKIX form. // The log's public key in DER-encoded PKIX form.
PublicKeyDer []byte `protobuf:"bytes,2,opt,name=public_key_der,json=publicKeyDer,proto3" json:"public_key_der,omitempty"` PublicKeyDer []byte `protobuf:"bytes,2,opt,name=public_key_der,json=publicKeyDer,proto3" json:"public_key_der,omitempty"`
// not_after_start defines the start of the range of acceptable NotAfter // not_after_start defines the start of the range of acceptable NotAfter
// values, inclusive. // values, inclusive.
// Leaving this unset implies no lower bound to the range. // Leaving this unset implies no lower bound to the range.
NotAfterStart *timestamp.Timestamp `protobuf:"bytes,3,opt,name=not_after_start,json=notAfterStart" json:"not_after_start,omitempty"` NotAfterStart *timestamp.Timestamp `protobuf:"bytes,3,opt,name=not_after_start,json=notAfterStart,proto3" json:"not_after_start,omitempty"`
// not_after_limit defines the end of the range of acceptable NotAfter values, // not_after_limit defines the end of the range of acceptable NotAfter values,
// exclusive. // exclusive.
// Leaving this unset implies no upper bound to the range. // Leaving this unset implies no upper bound to the range.
NotAfterLimit *timestamp.Timestamp `protobuf:"bytes,4,opt,name=not_after_limit,json=notAfterLimit" json:"not_after_limit,omitempty"` NotAfterLimit *timestamp.Timestamp `protobuf:"bytes,4,opt,name=not_after_limit,json=notAfterLimit,proto3" json:"not_after_limit,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`

View File

@ -0,0 +1,10 @@
steps:
- id: build_ctfe
name: gcr.io/cloud-builders/docker
args:
- build
- --file=trillian/examples/deployment/docker/ctfe/Dockerfile
- --tag=gcr.io/${PROJECT_ID}/ctfe:${TAG_NAME}
- .
images:
- gcr.io/${PROJECT_ID}/ctfe:${TAG_NAME}

View File

@ -1,4 +1,5 @@
{ {
"Deadline": "60s",
"Linters": { "Linters": {
"license": "./scripts/check_license.sh:PATH:LINE:MESSAGE", "license": "./scripts/check_license.sh:PATH:LINE:MESSAGE",
"forked": "./scripts/check_forked.sh:PATH:LINE:MESSAGE", "forked": "./scripts/check_forked.sh:PATH:LINE:MESSAGE",

View File

@ -0,0 +1,37 @@
all: ca
# The following private keys are never regenerated.
SERVER_PRIVKEYS=gossiper.privkey.pem
# Server public keys are derived from the corresponding private keys.
SERVER_PUBKEYS=$(subst .privkey,.pubkey,$(SERVER_PRIVKEYS))
# Build public keys from private keys
pubkeys: $(SERVER_PUBKEYS)
gossiper.pubkey.pem: gossiper.privkey.pem
openssl ec -in $< -pubout -out $@ -passin pass:$(GOSSIPER_PWD)
ROOT_CA_PRIVKEY=gossiper.privkey.pem
ROOT_CA_PWD=hissing-sid
ca: root-ca.cert
# Fake Root CA
root-ca.cert: gossiper.privkey.pem root-ca.cfg
openssl req -new -x509 -config root-ca.cfg -set_serial 0x0406cafe -days 3650 -extensions v3_ca -inform pem -key gossiper.privkey.pem -passin pass:$(ROOT_CA_PWD) -out $@
show-ca: root-ca.cert
openssl x509 -inform pem -in $< -text -noout
# clean removes things that regenerate exactly the same.
clean:
rm -f $(SERVER_PUBKEYS)
# distclean removes things that regenerate with changes (e.g. timestamped, randomized).
distclean: clean
rm -f $(SERVER_PUBKEYS) root-ca.cert
# The newkey target creates a fresh private key; should never be needed.
newkey: fresh.privkey.pem
fresh.privkey.pem:
openssl ecparam -genkey -name prime256v1 -noout -out $@.unencrypted
openssl ec -in $@.unencrypted -out $@ -des # Prompts for password
rm -f $@.unencrypted

View File

@ -0,0 +1,32 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d\xb9"
}
>
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source-2"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d\xb9"
}
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,17 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d\xb9"
}
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>

View File

@ -0,0 +1,8 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-CBC,559BE893ECD7A88C
UOwSw+WlSv5LLiBZSCnR12FX13Hk1a3vavdpUde4W4qawQgJSMqLa3it8Lfadtnm
GfGVqN+gF5KFiNWxgMs2qRcbdQ03ZlMmoH8Z8jPQHXvKseJvME8tZQWPvJ15rbXh
G9Lcx7NYlm0miHPy3ras8ci58HSDqz9Z7yOdgHzPpiU=
-----END EC PRIVATE KEY-----

View File

@ -0,0 +1,27 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d\xb9"
}
>
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source-2"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d\xb9"
}
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>

View File

@ -0,0 +1,13 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>

View File

@ -0,0 +1,7 @@
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>

View File

@ -0,0 +1,13 @@
source_log: <
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>

View File

@ -0,0 +1,19 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gone.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,19 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CARTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,20 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 10
nanos: -20
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,22 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d"
}
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,15 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d\xb9"
}
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,18 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,15 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"

View File

@ -0,0 +1,18 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,12 @@
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,18 @@
source_log: <
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQTCCAeegAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP
MA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds
ZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4
MDIyNTA4MTA1M1oXDTI4MDIyMzA4MTA1M1owaTELMAkGA1UEBhMCR0IxDzANBgNV
BAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK
BgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49
AgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH
ccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijfTB7MB0GA1UdDgQWBBRq
6hoXslGgHhrCVJMu4jrYlksyZjAfBgNVHSMEGDAWgBRq6hoXslGgHhrCVJMu4jrY
lksyZjASBgNVHRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwICBDAVBgNVHSUE
DjAMBgorBgEEAdZ5AgQGMAoGCCqGSM49BAMCA0gAMEUCIQCQCnWTIOlC6LqkcdH0
fWZeNo5E3AaZBb9Tkv76ET2fJAIgOeGJvfiiOIlDV41/bIOg5eTHb/fxg80TCQBe
6ia6ZS8=
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
# OpenSSL configuration file.
[ req ]
# Options for the `req` tool (`man req`).
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
# Try to force use of PrintableString throughout
string_mask = pkix
[ req_distinguished_name ]
C=GB
ST=London
L=London
O=Google
OU=Eng
CN=TestGossiperRoot
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:3
keyUsage = critical, keyCertSign
extendedKeyUsage = 1.3.6.1.4.1.11129.2.4.6

View File

@ -0,0 +1,22 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
public_key: {
der: "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\x07\xf8\x51\xaf\xaa\x8c\x56\x83\x90\x31\xb7\x80\xe3\xd6\x1a\xf7\x2f\x36\x06\x71\xec\xdd\x3b\xbe\x7e\x36\x6f\x0d\x1c\x1c\x60\x0b\x7f\xf5\x9f\xff\xe5\x24\x49\x34\x56\xf2\x4b\x10\x5f\xbf\x08\x1f\xf9\x0e\xcf\x35\xb5\x8a\x8a\x8b\x30\x0a\x54\xb7\xbf\x1d\x4d\xb9"
}
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013hissing-sid"
>

View File

@ -0,0 +1,19 @@
source_log: <
name: "theSourceOfAllSTHs"
url: "http://example.com/ct-source"
min_req_interval: <
seconds: 3600
>
>
dest_log: <
name: "theDestinationOfAllSTHs"
url: "http://example.com/ct-dest"
min_req_interval: <
seconds: 60
>
>
root_cert: "-----BEGIN CERTIFICATE-----\nMIICCzCCAbCgAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP\nMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds\nZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4\nMDIyMzEzNDUyOVoXDTI4MDIyMTEzNDUyOVowaTELMAkGA1UEBhMCR0IxDzANBgNV\nBAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK\nBgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49\nAgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH\nccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijRjBEMA0GA1UdDgQGBAQR\nEhMUMA8GA1UdIwQIMAaABBESExQwEgYDVR0TAQH/BAgwBgEB/wIBAzAOBgNVHQ8B\nAf8EBAMCAgQwCgYIKoZIzj0EAwIDSQAwRgIhAICXxzQ+EulZALo8em3KujsOCpNY\n6lvLF5lqBMLS9fxwAiEAkh54N7Dq6P+3Sl/u15TA5DKhFPqgnvnB51wXGAsDhN0=\n-----END CERTIFICATE-----"
private_key: <
type_url: "type.googleapis.com/keyspb.PEMKeyFile"
value: "\n\035testdata/gossiper.privkey.pem\022\013passing-sid"
>

View File

@ -0,0 +1,91 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package x509ext holds extensions types and values for minimal gossip.
package x509ext
import (
"errors"
"fmt"
"github.com/google/certificate-transparency-go"
"github.com/google/certificate-transparency-go/asn1"
"github.com/google/certificate-transparency-go/tls"
"github.com/google/certificate-transparency-go/x509"
)
// OIDExtensionCTSTH is the OID value for an X.509 extension that holds
// a log STH value.
// TODO(drysdale): get an official OID value
var OIDExtensionCTSTH = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 5}
// OIDExtKeyUsageCTMinimalGossip is the OID value for an extended key usage
// (EKU) that indicates a leaf certificate is used for the validation of STH
// values from public CT logs.
// TODO(drysdale): get an official OID value
var OIDExtKeyUsageCTMinimalGossip = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 6}
// LogSTHInfo is the structure that gets TLS-encoded into the X.509 extension
// identified by OIDExtensionCTSTH.
type LogSTHInfo struct {
LogURL []byte `tls:"maxlen:255"`
Version tls.Enum `tls:"maxval:255"`
TreeSize uint64
Timestamp uint64
SHA256RootHash ct.SHA256Hash
TreeHeadSignature ct.DigitallySigned
}
// LogSTHInfoFromCert retrieves the STH information embedded in a certificate.
func LogSTHInfoFromCert(cert *x509.Certificate) (*LogSTHInfo, error) {
for _, ext := range cert.Extensions {
if ext.Id.Equal(OIDExtensionCTSTH) {
var sthInfo LogSTHInfo
rest, err := tls.Unmarshal(ext.Value, &sthInfo)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal STH: %v", err)
} else if len(rest) > 0 {
return nil, fmt.Errorf("trailing data (%d bytes) after STH", len(rest))
}
return &sthInfo, nil
}
}
return nil, errors.New("no STH extension found")
}
// HasSTHInfo indicates whether a certificate has embedded STH information.
func HasSTHInfo(cert *x509.Certificate) bool {
for _, ext := range cert.Extensions {
if ext.Id.Equal(OIDExtensionCTSTH) {
return true
}
}
return false
}
// STHFromCert retrieves the STH embedded in a certificate; note the returned STH
// does not have the LogID field filled in.
func STHFromCert(cert *x509.Certificate) (*ct.SignedTreeHead, error) {
sthInfo, err := LogSTHInfoFromCert(cert)
if err != nil {
return nil, err
}
return &ct.SignedTreeHead{
Version: ct.Version(sthInfo.Version),
TreeSize: sthInfo.TreeSize,
Timestamp: sthInfo.Timestamp,
SHA256RootHash: sthInfo.SHA256RootHash,
TreeHeadSignature: sthInfo.TreeHeadSignature,
}, nil
}

View File

@ -0,0 +1,150 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package x509ext_test
import (
"encoding/hex"
"encoding/pem"
"fmt"
"strings"
"testing"
"time"
"github.com/google/certificate-transparency-go"
"github.com/google/certificate-transparency-go/gossip/minimal/x509ext"
"github.com/google/certificate-transparency-go/tls"
"github.com/google/certificate-transparency-go/x509"
"github.com/google/certificate-transparency-go/x509/pkix"
)
var (
// pilotPubKeyPEM is the public key for Google's Pilot log.
pilotPubKeyPEM = []byte(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHT
DM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==
-----END PUBLIC KEY-----`)
)
func TestSTHFromCert(t *testing.T) {
rawPubKey, _ := pem.Decode(pilotPubKeyPEM)
pubKey, _, _, err := ct.PublicKeyFromPEM(pilotPubKeyPEM)
if err != nil {
t.Fatalf("failed to decode test pubkey data: %v", err)
}
validSTH := x509ext.LogSTHInfo{
LogURL: []byte("http://ct.example.com/log"),
Version: 0,
TreeSize: 7834120,
Timestamp: 1519395540364,
SHA256RootHash: [...]byte{
0xfe, 0xc0, 0xed, 0xe1, 0xbe, 0xf1, 0xa2, 0x25, 0xc3, 0x72, 0xa6, 0x44, 0x1b, 0xa2, 0xd5, 0xdd, 0x3b, 0xbb, 0x9b, 0x7b, 0xa9, 0x79, 0xd1, 0xa7, 0x03, 0xe7, 0xfe, 0x81, 0x49, 0x75, 0x85, 0xfb,
},
TreeHeadSignature: ct.DigitallySigned{
Algorithm: tls.SignatureAndHashAlgorithm{Hash: tls.SHA256, Signature: tls.ECDSA},
Signature: dehex("220164e031604aa2a0b68887ba668cefb3e0046e455d6323c3df38b8d50108895d70220146199ee1d759a029d8b37ce8701d2ca47a387bad8ac8ef1cb84b77bc0820ed"),
},
}
sthData, err := tls.Marshal(validSTH)
if err != nil {
t.Fatalf("failed to marshal STH: %v", err)
}
var tests = []struct {
name string
cert x509.Certificate
wantErr string
}{
{
name: "ValidSTH",
cert: x509.Certificate{
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
PublicKey: pubKey,
RawSubjectPublicKeyInfo: rawPubKey.Bytes,
Subject: pkix.Name{
CommonName: "Test STH holder",
},
Extensions: []pkix.Extension{
{Id: x509ext.OIDExtensionCTSTH, Critical: false, Value: sthData},
},
},
},
{
name: "MissingSTH",
cert: x509.Certificate{
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
Subject: pkix.Name{
CommonName: "Test STH holder",
},
},
wantErr: "no STH extension found",
},
{
name: "TrailingData",
cert: x509.Certificate{
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
Subject: pkix.Name{
CommonName: "Test STH holder",
},
Extensions: []pkix.Extension{
{Id: x509ext.OIDExtensionCTSTH, Critical: false, Value: append(sthData, 0xff)},
},
},
wantErr: "trailing data",
},
{
name: "InvalidSTH",
cert: x509.Certificate{
NotBefore: time.Now(),
NotAfter: time.Now().Add(24 * time.Hour),
Subject: pkix.Name{
CommonName: "Test STH holder",
},
Extensions: []pkix.Extension{
{Id: x509ext.OIDExtensionCTSTH, Critical: false, Value: []byte{0xff}},
},
},
wantErr: "failed to unmarshal",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got, err := x509ext.STHFromCert(&test.cert)
if err != nil {
if test.wantErr == "" {
t.Errorf("STHFromCert(%+v)=nil,%v; want _,nil", test.cert, err)
} else if !strings.Contains(err.Error(), test.wantErr) {
t.Errorf("STHFromCert(%+v)=nil,%v; want nil,err containing %q", test.cert, err, test.wantErr)
}
return
}
if test.wantErr != "" {
t.Errorf("STHFromCert(%+v)=_,nil; want nil,err containing %q", test.cert, test.wantErr)
}
t.Logf("retrieved STH %+v", got)
})
}
}
func dehex(h string) []byte {
d, err := hex.DecodeString(h)
if err != nil {
panic(fmt.Sprintf("hard-coded data %q failed to decode! %v", h, err))
}
return d
}

View File

@ -22,7 +22,6 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"encoding/pem" "encoding/pem"
"flag"
"fmt" "fmt"
"log" "log"
@ -30,8 +29,10 @@ import (
"github.com/google/certificate-transparency-go/x509" "github.com/google/certificate-transparency-go/x509"
) )
var allowVerificationWithNonCompliantKeys = flag.Bool("allow_verification_with_non_compliant_keys", false, // AllowVerificationWithNonCompliantKeys may be set to true in order to allow
"Allow a SignatureVerifier to use keys which are technically non-compliant with RFC6962.") // SignatureVerifier to use keys which are technically non-compliant with
// RFC6962.
var AllowVerificationWithNonCompliantKeys = false
// PublicKeyFromPEM parses a PEM formatted block and returns the public key contained within and any remaining unread bytes, or an error. // PublicKeyFromPEM parses a PEM formatted block and returns the public key contained within and any remaining unread bytes, or an error.
func PublicKeyFromPEM(b []byte) (crypto.PublicKey, SHA256Hash, []byte, error) { func PublicKeyFromPEM(b []byte) (crypto.PublicKey, SHA256Hash, []byte, error) {
@ -63,7 +64,7 @@ func NewSignatureVerifier(pk crypto.PublicKey) (*SignatureVerifier, error) {
case *rsa.PublicKey: case *rsa.PublicKey:
if pkType.N.BitLen() < 2048 { if pkType.N.BitLen() < 2048 {
e := fmt.Errorf("public key is RSA with < 2048 bits (size:%d)", pkType.N.BitLen()) e := fmt.Errorf("public key is RSA with < 2048 bits (size:%d)", pkType.N.BitLen())
if !(*allowVerificationWithNonCompliantKeys) { if !AllowVerificationWithNonCompliantKeys {
return nil, e return nil, e
} }
log.Printf("WARNING: %v", e) log.Printf("WARNING: %v", e)
@ -72,7 +73,7 @@ func NewSignatureVerifier(pk crypto.PublicKey) (*SignatureVerifier, error) {
params := *(pkType.Params()) params := *(pkType.Params())
if params != *elliptic.P256().Params() { if params != *elliptic.P256().Params() {
e := fmt.Errorf("public is ECDSA, but not on the P256 curve") e := fmt.Errorf("public is ECDSA, but not on the P256 curve")
if !(*allowVerificationWithNonCompliantKeys) { if !AllowVerificationWithNonCompliantKeys {
return nil, e return nil, e
} }
log.Printf("WARNING: %v", e) log.Printf("WARNING: %v", e)

View File

@ -471,7 +471,7 @@ func TestNewSignatureVerifierFailsWithBadKeyParametersForRSA(t *testing.T) {
} }
func TestWillAllowNonCompliantECKeyWithOverride(t *testing.T) { func TestWillAllowNonCompliantECKeyWithOverride(t *testing.T) {
*allowVerificationWithNonCompliantKeys = true AllowVerificationWithNonCompliantKeys = true
k, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) k, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
if err != nil { if err != nil {
t.Fatalf("Failed to generate EC key on P224: %v", err) t.Fatalf("Failed to generate EC key on P224: %v", err)
@ -482,7 +482,7 @@ func TestWillAllowNonCompliantECKeyWithOverride(t *testing.T) {
} }
func TestWillAllowNonCompliantRSAKeyWithOverride(t *testing.T) { func TestWillAllowNonCompliantRSAKeyWithOverride(t *testing.T) {
*allowVerificationWithNonCompliantKeys = true AllowVerificationWithNonCompliantKeys = true
k, err := rsa.GenerateKey(rand.Reader, 1024) k, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil { if err != nil {
t.Fatalf("Failed to generate 1024 bit RSA key: %v", err) t.Fatalf("Failed to generate 1024 bit RSA key: %v", err)

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQTCCAeegAwIBAgIEBAbK/jAKBggqhkjOPQQDAjBpMQswCQYDVQQGEwJHQjEP
MA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xDzANBgNVBAoTBkdvb2ds
ZTEMMAoGA1UECxMDRW5nMRkwFwYDVQQDExBUZXN0R29zc2lwZXJSb290MB4XDTE4
MDIyNTA4MTA1M1oXDTI4MDIyMzA4MTA1M1owaTELMAkGA1UEBhMCR0IxDzANBgNV
BAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMQ8wDQYDVQQKEwZHb29nbGUxDDAK
BgNVBAsTA0VuZzEZMBcGA1UEAxMQVGVzdEdvc3NpcGVyUm9vdDBZMBMGByqGSM49
AgEGCCqGSM49AwEHA0IABOqzZufPSU6hMJOIbljkjklDvQKBGYW9VenI6i7HSiyH
ccPUuh3F3fbbe2MrLtuRCjH7nqvcELPqBJsL3IVgQJijfTB7MB0GA1UdDgQWBBRq
6hoXslGgHhrCVJMu4jrYlksyZjAfBgNVHSMEGDAWgBRq6hoXslGgHhrCVJMu4jrY
lksyZjASBgNVHRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwICBDAVBgNVHSUE
DjAMBgorBgEEAdZ5AgQGMAoGCCqGSM49BAMCA0gAMEUCIQCQCnWTIOlC6LqkcdH0
fWZeNo5E3AaZBb9Tkv76ET2fJAIgOeGJvfiiOIlDV41/bIOg5eTHb/fxg80TCQBe
6ia6ZS8=
-----END CERTIFICATE-----

View File

@ -0,0 +1,8 @@
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-CBC,559BE893ECD7A88C
UOwSw+WlSv5LLiBZSCnR12FX13Hk1a3vavdpUde4W4qawQgJSMqLa3it8Lfadtnm
GfGVqN+gF5KFiNWxgMs2qRcbdQ03ZlMmoH8Z8jPQHXvKseJvME8tZQWPvJ15rbXh
G9Lcx7NYlm0miHPy3ras8ci58HSDqz9Z7yOdgHzPpiU=
-----END EC PRIVATE KEY-----

View File

@ -374,7 +374,27 @@ func (m *MerkleTreeLeaf) Precertificate() (*x509.Certificate, error) {
return x509.ParseTBSCertificate(m.TimestampedEntry.PrecertEntry.TBSCertificate) return x509.ParseTBSCertificate(m.TimestampedEntry.PrecertEntry.TBSCertificate)
} }
// APIEndpoint is a string that represents one of the Certificate Transparency
// Log API endpoints.
type APIEndpoint string
// Certificate Transparency Log API endpoints; see section 4.
// WARNING: Should match the URI paths without the "/ct/v1/" prefix. If
// changing these constants, may need to change those too.
const (
AddChainStr APIEndpoint = "add-chain"
AddPreChainStr APIEndpoint = "add-pre-chain"
GetSTHStr APIEndpoint = "get-sth"
GetEntriesStr APIEndpoint = "get-entries"
GetProofByHashStr APIEndpoint = "get-proof-by-hash"
GetSTHConsistencyStr APIEndpoint = "get-sth-consistency"
GetRootsStr APIEndpoint = "get-roots"
GetEntryAndProofStr APIEndpoint = "get-entry-and-proof"
)
// URI paths for Log requests; see section 4. // URI paths for Log requests; see section 4.
// WARNING: Should match the API endpoints, with the "/ct/v1/" prefix. If
// changing these constants, may need to change those too.
const ( const (
AddChainPath = "/ct/v1/add-chain" AddChainPath = "/ct/v1/add-chain"
AddPreChainPath = "/ct/v1/add-pre-chain" AddPreChainPath = "/ct/v1/add-pre-chain"

View File

@ -0,0 +1,20 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11
package x509
import (
"syscall"
"unsafe"
)
// For Go versions >= 1.11, the ExtraPolicyPara field in
// syscall.CertChainPolicyPara is of type syscall.Pointer. See:
// https://github.com/golang/go/commit/4869ec00e87ef
func convertToPolicyParaType(p unsafe.Pointer) syscall.Pointer {
return (syscall.Pointer)(p)
}

View File

@ -0,0 +1,17 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.11
package x509
import "unsafe"
// For Go versions before 1.11, the ExtraPolicyPara field in
// syscall.CertChainPolicyPara was of type uintptr. See:
// https://github.com/golang/go/commit/4869ec00e87ef
func convertToPolicyParaType(p unsafe.Pointer) uintptr {
return uintptr(p)
}

View File

@ -109,7 +109,7 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
sslPara.Size = uint32(unsafe.Sizeof(*sslPara)) sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
para := &syscall.CertChainPolicyPara{ para := &syscall.CertChainPolicyPara{
ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)), ExtraPolicyPara: convertToPolicyParaType(unsafe.Pointer(sslPara)),
} }
para.Size = uint32(unsafe.Sizeof(*para)) para.Size = uint32(unsafe.Sizeof(*para))

View File

@ -1446,7 +1446,7 @@ func isValidIPMask(mask []byte) bool {
return true return true
} }
func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) { func parseNameConstraintsExtension(out *Certificate, e pkix.Extension, nfe *NonFatalErrors) (unhandled bool, err error) {
// RFC 5280, 4.2.1.10 // RFC 5280, 4.2.1.10
// NameConstraints ::= SEQUENCE { // NameConstraints ::= SEQUENCE {
@ -1513,7 +1513,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
trimmedDomain = trimmedDomain[1:] trimmedDomain = trimmedDomain[1:]
} }
if _, ok := domainToReverseLabels(trimmedDomain); !ok { if _, ok := domainToReverseLabels(trimmedDomain); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) nfe.AddError(fmt.Errorf("x509: failed to parse dnsName constraint %q", domain))
} }
dnsNames = append(dnsNames, domain) dnsNames = append(dnsNames, domain)
@ -1550,7 +1550,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
// it specifies an exact mailbox name. // it specifies an exact mailbox name.
if strings.Contains(constraint, "@") { if strings.Contains(constraint, "@") {
if _, ok := parseRFC2821Mailbox(constraint); !ok { if _, ok := parseRFC2821Mailbox(constraint); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) nfe.AddError(fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint))
} }
} else { } else {
// Otherwise it's a domain name. // Otherwise it's a domain name.
@ -1559,7 +1559,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
domain = domain[1:] domain = domain[1:]
} }
if _, ok := domainToReverseLabels(domain); !ok { if _, ok := domainToReverseLabels(domain); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) nfe.AddError(fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint))
} }
} }
emails = append(emails, constraint) emails = append(emails, constraint)
@ -1583,7 +1583,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
trimmedDomain = trimmedDomain[1:] trimmedDomain = trimmedDomain[1:]
} }
if _, ok := domainToReverseLabels(trimmedDomain); !ok { if _, ok := domainToReverseLabels(trimmedDomain); !ok {
return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) nfe.AddError(fmt.Errorf("x509: failed to parse URI constraint %q", domain))
} }
uriDomains = append(uriDomains, domain) uriDomains = append(uriDomains, domain)
@ -1698,7 +1698,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
} }
case OIDExtensionNameConstraints[3]: case OIDExtensionNameConstraints[3]:
unhandled, err = parseNameConstraintsExtension(out, e) unhandled, err = parseNameConstraintsExtension(out, e, &nfe)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1834,6 +1834,8 @@ func ParseTBSCertificate(asn1Data []byte) (*Certificate, error) {
} }
// ParseCertificate parses a single certificate from the given ASN.1 DER data. // ParseCertificate parses a single certificate from the given ASN.1 DER data.
// This function can return both a Certificate and an error (in which case the
// error will be of type NonFatalErrors).
func ParseCertificate(asn1Data []byte) (*Certificate, error) { func ParseCertificate(asn1Data []byte) (*Certificate, error) {
var cert certificate var cert certificate
rest, err := asn1.Unmarshal(asn1Data, &cert) rest, err := asn1.Unmarshal(asn1Data, &cert)
@ -1849,6 +1851,8 @@ func ParseCertificate(asn1Data []byte) (*Certificate, error) {
// ParseCertificates parses one or more certificates from the given ASN.1 DER // ParseCertificates parses one or more certificates from the given ASN.1 DER
// data. The certificates must be concatenated with no intermediate padding. // data. The certificates must be concatenated with no intermediate padding.
// This function can return both a slice of Certificate and an error (in which
// case the error will be of type NonFatalErrors).
func ParseCertificates(asn1Data []byte) ([]*Certificate, error) { func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
var v []*certificate var v []*certificate
@ -1862,15 +1866,23 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
v = append(v, cert) v = append(v, cert)
} }
var nfe NonFatalErrors
ret := make([]*Certificate, len(v)) ret := make([]*Certificate, len(v))
for i, ci := range v { for i, ci := range v {
cert, err := parseCertificate(ci) cert, err := parseCertificate(ci)
if err != nil { if err != nil {
if errs, ok := err.(NonFatalErrors); !ok {
return nil, err return nil, err
} else {
nfe.Errors = append(nfe.Errors, errs.Errors...)
}
} }
ret[i] = cert ret[i] = cert
} }
if nfe.HasError() {
return ret, nfe
}
return ret, nil return ret, nil
} }

View File

@ -31,6 +31,7 @@ import (
ct "github.com/google/certificate-transparency-go" ct "github.com/google/certificate-transparency-go"
"github.com/google/certificate-transparency-go/asn1" "github.com/google/certificate-transparency-go/asn1"
"github.com/google/certificate-transparency-go/gossip/minimal/x509ext"
"github.com/google/certificate-transparency-go/tls" "github.com/google/certificate-transparency-go/tls"
"github.com/google/certificate-transparency-go/x509" "github.com/google/certificate-transparency-go/x509"
"github.com/google/certificate-transparency-go/x509/pkix" "github.com/google/certificate-transparency-go/x509/pkix"
@ -426,6 +427,7 @@ func CertificateToString(cert *x509.Certificate) string {
showAuthInfoAccess(&result, cert) showAuthInfoAccess(&result, cert)
showCTPoison(&result, cert) showCTPoison(&result, cert)
showCTSCT(&result, cert) showCTSCT(&result, cert)
showCTLogSTHInfo(&result, cert)
showUnhandledExtensions(&result, cert) showUnhandledExtensions(&result, cert)
showSignature(&result, cert) showSignature(&result, cert)
@ -621,6 +623,30 @@ func showCTSCT(result *bytes.Buffer, cert *x509.Certificate) {
} }
} }
func showCTLogSTHInfo(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509ext.OIDExtensionCTSTH, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" Certificate Transparency STH:"))
showCritical(result, critical)
sthInfo, err := x509ext.LogSTHInfoFromCert(cert)
if err != nil {
result.WriteString(fmt.Sprintf(" Failed to decode STH:\n"))
return
}
result.WriteString(fmt.Sprintf(" LogURL: %s\n", string(sthInfo.LogURL)))
result.WriteString(fmt.Sprintf(" Version: %d\n", sthInfo.Version))
result.WriteString(fmt.Sprintf(" TreeSize: %d\n", sthInfo.TreeSize))
result.WriteString(fmt.Sprintf(" Timestamp: %d\n", sthInfo.Timestamp))
result.WriteString(fmt.Sprintf(" RootHash:\n"))
appendHexData(result, sthInfo.SHA256RootHash[:], 16, " ")
result.WriteString("\n")
result.WriteString(fmt.Sprintf(" TreeHeadSignature: %s\n", sthInfo.TreeHeadSignature.Algorithm))
result.WriteString(fmt.Sprintf(" TreeHeadSignature:\n"))
appendHexData(result, sthInfo.TreeHeadSignature.Signature, 16, " ")
result.WriteString("\n")
}
}
func showUnhandledExtensions(result *bytes.Buffer, cert *x509.Certificate) { func showUnhandledExtensions(result *bytes.Buffer, cert *x509.Certificate) {
for _, ext := range cert.Extensions { for _, ext := range cert.Extensions {
// Skip extensions that are already cracked out // Skip extensions that are already cracked out
@ -653,7 +679,8 @@ func oidAlreadyPrinted(oid asn1.ObjectIdentifier) bool {
oid.Equal(x509.OIDExtensionCRLDistributionPoints) || oid.Equal(x509.OIDExtensionCRLDistributionPoints) ||
oid.Equal(x509.OIDExtensionAuthorityInfoAccess) || oid.Equal(x509.OIDExtensionAuthorityInfoAccess) ||
oid.Equal(x509.OIDExtensionCTPoison) || oid.Equal(x509.OIDExtensionCTPoison) ||
oid.Equal(x509.OIDExtensionCTSCT) { oid.Equal(x509.OIDExtensionCTSCT) ||
oid.Equal(x509ext.OIDExtensionCTSTH) {
return true return true
} }
return false return false
@ -717,8 +744,10 @@ func ExtractSCT(sctData *x509.SerializedSCT) (*ct.SignedCertificateTimestamp, er
return nil, errors.New("SCT is nil") return nil, errors.New("SCT is nil")
} }
var sct ct.SignedCertificateTimestamp var sct ct.SignedCertificateTimestamp
if _, err := tls.Unmarshal(sctData.Val, &sct); err != nil { if rest, err := tls.Unmarshal(sctData.Val, &sct); err != nil {
return nil, fmt.Errorf("error parsing SCT: %s", err) return nil, fmt.Errorf("error parsing SCT: %s", err)
} else if len(rest) > 0 {
return nil, fmt.Errorf("extra data (%d bytes) after serialized SCT", len(rest))
} }
return &sct, nil return &sct, nil
} }

4
vendor/github.com/kr/pretty/.gitignore generated vendored Normal file
View File

@ -0,0 +1,4 @@
[568].out
_go*
_test*
_obj

21
vendor/github.com/kr/pretty/License generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright 2012 Keith Rarick
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.

9
vendor/github.com/kr/pretty/Readme generated vendored Normal file
View File

@ -0,0 +1,9 @@
package pretty
import "github.com/kr/pretty"
Package pretty provides pretty-printing for Go values.
Documentation
http://godoc.org/github.com/kr/pretty

265
vendor/github.com/kr/pretty/diff.go generated vendored Normal file
View File

@ -0,0 +1,265 @@
package pretty
import (
"fmt"
"io"
"reflect"
)
type sbuf []string
func (p *sbuf) Printf(format string, a ...interface{}) {
s := fmt.Sprintf(format, a...)
*p = append(*p, s)
}
// Diff returns a slice where each element describes
// a difference between a and b.
func Diff(a, b interface{}) (desc []string) {
Pdiff((*sbuf)(&desc), a, b)
return desc
}
// wprintfer calls Fprintf on w for each Printf call
// with a trailing newline.
type wprintfer struct{ w io.Writer }
func (p *wprintfer) Printf(format string, a ...interface{}) {
fmt.Fprintf(p.w, format+"\n", a...)
}
// Fdiff writes to w a description of the differences between a and b.
func Fdiff(w io.Writer, a, b interface{}) {
Pdiff(&wprintfer{w}, a, b)
}
type Printfer interface {
Printf(format string, a ...interface{})
}
// Pdiff prints to p a description of the differences between a and b.
// It calls Printf once for each difference, with no trailing newline.
// The standard library log.Logger is a Printfer.
func Pdiff(p Printfer, a, b interface{}) {
diffPrinter{w: p}.diff(reflect.ValueOf(a), reflect.ValueOf(b))
}
type Logfer interface {
Logf(format string, a ...interface{})
}
// logprintfer calls Fprintf on w for each Printf call
// with a trailing newline.
type logprintfer struct{ l Logfer }
func (p *logprintfer) Printf(format string, a ...interface{}) {
p.l.Logf(format, a...)
}
// Ldiff prints to l a description of the differences between a and b.
// It calls Logf once for each difference, with no trailing newline.
// The standard library testing.T and testing.B are Logfers.
func Ldiff(l Logfer, a, b interface{}) {
Pdiff(&logprintfer{l}, a, b)
}
type diffPrinter struct {
w Printfer
l string // label
}
func (w diffPrinter) printf(f string, a ...interface{}) {
var l string
if w.l != "" {
l = w.l + ": "
}
w.w.Printf(l+f, a...)
}
func (w diffPrinter) diff(av, bv reflect.Value) {
if !av.IsValid() && bv.IsValid() {
w.printf("nil != %# v", formatter{v: bv, quote: true})
return
}
if av.IsValid() && !bv.IsValid() {
w.printf("%# v != nil", formatter{v: av, quote: true})
return
}
if !av.IsValid() && !bv.IsValid() {
return
}
at := av.Type()
bt := bv.Type()
if at != bt {
w.printf("%v != %v", at, bt)
return
}
switch kind := at.Kind(); kind {
case reflect.Bool:
if a, b := av.Bool(), bv.Bool(); a != b {
w.printf("%v != %v", a, b)
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if a, b := av.Int(), bv.Int(); a != b {
w.printf("%d != %d", a, b)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if a, b := av.Uint(), bv.Uint(); a != b {
w.printf("%d != %d", a, b)
}
case reflect.Float32, reflect.Float64:
if a, b := av.Float(), bv.Float(); a != b {
w.printf("%v != %v", a, b)
}
case reflect.Complex64, reflect.Complex128:
if a, b := av.Complex(), bv.Complex(); a != b {
w.printf("%v != %v", a, b)
}
case reflect.Array:
n := av.Len()
for i := 0; i < n; i++ {
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
}
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
if a, b := av.Pointer(), bv.Pointer(); a != b {
w.printf("%#x != %#x", a, b)
}
case reflect.Interface:
w.diff(av.Elem(), bv.Elem())
case reflect.Map:
ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys())
for _, k := range ak {
w := w.relabel(fmt.Sprintf("[%#v]", k))
w.printf("%q != (missing)", av.MapIndex(k))
}
for _, k := range both {
w := w.relabel(fmt.Sprintf("[%#v]", k))
w.diff(av.MapIndex(k), bv.MapIndex(k))
}
for _, k := range bk {
w := w.relabel(fmt.Sprintf("[%#v]", k))
w.printf("(missing) != %q", bv.MapIndex(k))
}
case reflect.Ptr:
switch {
case av.IsNil() && !bv.IsNil():
w.printf("nil != %# v", formatter{v: bv, quote: true})
case !av.IsNil() && bv.IsNil():
w.printf("%# v != nil", formatter{v: av, quote: true})
case !av.IsNil() && !bv.IsNil():
w.diff(av.Elem(), bv.Elem())
}
case reflect.Slice:
lenA := av.Len()
lenB := bv.Len()
if lenA != lenB {
w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB)
break
}
for i := 0; i < lenA; i++ {
w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i))
}
case reflect.String:
if a, b := av.String(), bv.String(); a != b {
w.printf("%q != %q", a, b)
}
case reflect.Struct:
for i := 0; i < av.NumField(); i++ {
w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i))
}
default:
panic("unknown reflect Kind: " + kind.String())
}
}
func (d diffPrinter) relabel(name string) (d1 diffPrinter) {
d1 = d
if d.l != "" && name[0] != '[' {
d1.l += "."
}
d1.l += name
return d1
}
// keyEqual compares a and b for equality.
// Both a and b must be valid map keys.
func keyEqual(av, bv reflect.Value) bool {
if !av.IsValid() && !bv.IsValid() {
return true
}
if !av.IsValid() || !bv.IsValid() || av.Type() != bv.Type() {
return false
}
switch kind := av.Kind(); kind {
case reflect.Bool:
a, b := av.Bool(), bv.Bool()
return a == b
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
a, b := av.Int(), bv.Int()
return a == b
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
a, b := av.Uint(), bv.Uint()
return a == b
case reflect.Float32, reflect.Float64:
a, b := av.Float(), bv.Float()
return a == b
case reflect.Complex64, reflect.Complex128:
a, b := av.Complex(), bv.Complex()
return a == b
case reflect.Array:
for i := 0; i < av.Len(); i++ {
if !keyEqual(av.Index(i), bv.Index(i)) {
return false
}
}
return true
case reflect.Chan, reflect.UnsafePointer, reflect.Ptr:
a, b := av.Pointer(), bv.Pointer()
return a == b
case reflect.Interface:
return keyEqual(av.Elem(), bv.Elem())
case reflect.String:
a, b := av.String(), bv.String()
return a == b
case reflect.Struct:
for i := 0; i < av.NumField(); i++ {
if !keyEqual(av.Field(i), bv.Field(i)) {
return false
}
}
return true
default:
panic("invalid map key type " + av.Type().String())
}
}
func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) {
for _, av := range a {
inBoth := false
for _, bv := range b {
if keyEqual(av, bv) {
inBoth = true
both = append(both, av)
break
}
}
if !inBoth {
ak = append(ak, av)
}
}
for _, bv := range b {
inBoth := false
for _, av := range a {
if keyEqual(av, bv) {
inBoth = true
break
}
}
if !inBoth {
bk = append(bk, bv)
}
}
return
}

213
vendor/github.com/kr/pretty/diff_test.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
package pretty
import (
"bytes"
"fmt"
"log"
"reflect"
"testing"
"unsafe"
)
var (
_ Logfer = (*testing.T)(nil)
_ Logfer = (*testing.B)(nil)
_ Printfer = (*log.Logger)(nil)
)
type difftest struct {
a interface{}
b interface{}
exp []string
}
type S struct {
A int
S *S
I interface{}
C []int
}
type (
N struct{ N int }
E interface{}
)
var (
c0 = make(chan int)
c1 = make(chan int)
f0 = func() {}
f1 = func() {}
i0 = 0
i1 = 1
)
var diffs = []difftest{
{a: nil, b: nil},
{a: S{A: 1}, b: S{A: 1}},
{0, "", []string{`int != string`}},
{0, 1, []string{`0 != 1`}},
{S{}, new(S), []string{`pretty.S != *pretty.S`}},
{"a", "b", []string{`"a" != "b"`}},
{S{}, S{A: 1}, []string{`A: 0 != 1`}},
{new(S), &S{A: 1}, []string{`A: 0 != 1`}},
{S{S: new(S)}, S{S: &S{A: 1}}, []string{`S.A: 0 != 1`}},
{S{}, S{I: 0}, []string{`I: nil != int(0)`}},
{S{I: 1}, S{I: "x"}, []string{`I: int != string`}},
{S{}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
{S{C: []int{}}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}},
{S{C: []int{1, 2, 3}}, S{C: []int{1, 2, 4}}, []string{`C[2]: 3 != 4`}},
{S{}, S{A: 1, S: new(S)}, []string{`A: 0 != 1`, `S: nil != &pretty.S{}`}},
// unexported fields of every reflect.Kind (both equal and unequal)
{struct{ x bool }{false}, struct{ x bool }{false}, nil},
{struct{ x bool }{false}, struct{ x bool }{true}, []string{`x: false != true`}},
{struct{ x int }{0}, struct{ x int }{0}, nil},
{struct{ x int }{0}, struct{ x int }{1}, []string{`x: 0 != 1`}},
{struct{ x int8 }{0}, struct{ x int8 }{0}, nil},
{struct{ x int8 }{0}, struct{ x int8 }{1}, []string{`x: 0 != 1`}},
{struct{ x int16 }{0}, struct{ x int16 }{0}, nil},
{struct{ x int16 }{0}, struct{ x int16 }{1}, []string{`x: 0 != 1`}},
{struct{ x int32 }{0}, struct{ x int32 }{0}, nil},
{struct{ x int32 }{0}, struct{ x int32 }{1}, []string{`x: 0 != 1`}},
{struct{ x int64 }{0}, struct{ x int64 }{0}, nil},
{struct{ x int64 }{0}, struct{ x int64 }{1}, []string{`x: 0 != 1`}},
{struct{ x uint }{0}, struct{ x uint }{0}, nil},
{struct{ x uint }{0}, struct{ x uint }{1}, []string{`x: 0 != 1`}},
{struct{ x uint8 }{0}, struct{ x uint8 }{0}, nil},
{struct{ x uint8 }{0}, struct{ x uint8 }{1}, []string{`x: 0 != 1`}},
{struct{ x uint16 }{0}, struct{ x uint16 }{0}, nil},
{struct{ x uint16 }{0}, struct{ x uint16 }{1}, []string{`x: 0 != 1`}},
{struct{ x uint32 }{0}, struct{ x uint32 }{0}, nil},
{struct{ x uint32 }{0}, struct{ x uint32 }{1}, []string{`x: 0 != 1`}},
{struct{ x uint64 }{0}, struct{ x uint64 }{0}, nil},
{struct{ x uint64 }{0}, struct{ x uint64 }{1}, []string{`x: 0 != 1`}},
{struct{ x uintptr }{0}, struct{ x uintptr }{0}, nil},
{struct{ x uintptr }{0}, struct{ x uintptr }{1}, []string{`x: 0 != 1`}},
{struct{ x float32 }{0}, struct{ x float32 }{0}, nil},
{struct{ x float32 }{0}, struct{ x float32 }{1}, []string{`x: 0 != 1`}},
{struct{ x float64 }{0}, struct{ x float64 }{0}, nil},
{struct{ x float64 }{0}, struct{ x float64 }{1}, []string{`x: 0 != 1`}},
{struct{ x complex64 }{0}, struct{ x complex64 }{0}, nil},
{struct{ x complex64 }{0}, struct{ x complex64 }{1}, []string{`x: (0+0i) != (1+0i)`}},
{struct{ x complex128 }{0}, struct{ x complex128 }{0}, nil},
{struct{ x complex128 }{0}, struct{ x complex128 }{1}, []string{`x: (0+0i) != (1+0i)`}},
{struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{0}}, nil},
{struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{1}}, []string{`x[0]: 0 != 1`}},
{struct{ x chan int }{c0}, struct{ x chan int }{c0}, nil},
{struct{ x chan int }{c0}, struct{ x chan int }{c1}, []string{fmt.Sprintf("x: %p != %p", c0, c1)}},
{struct{ x func() }{f0}, struct{ x func() }{f0}, nil},
{struct{ x func() }{f0}, struct{ x func() }{f1}, []string{fmt.Sprintf("x: %p != %p", f0, f1)}},
{struct{ x interface{} }{0}, struct{ x interface{} }{0}, nil},
{struct{ x interface{} }{0}, struct{ x interface{} }{1}, []string{`x: 0 != 1`}},
{struct{ x interface{} }{0}, struct{ x interface{} }{""}, []string{`x: int != string`}},
{struct{ x interface{} }{0}, struct{ x interface{} }{nil}, []string{`x: int(0) != nil`}},
{struct{ x interface{} }{nil}, struct{ x interface{} }{0}, []string{`x: nil != int(0)`}},
{struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 0}}, nil},
{struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 1}}, []string{`x[0]: 0 != 1`}},
{struct{ x *int }{new(int)}, struct{ x *int }{new(int)}, nil},
{struct{ x *int }{&i0}, struct{ x *int }{&i1}, []string{`x: 0 != 1`}},
{struct{ x *int }{nil}, struct{ x *int }{&i0}, []string{`x: nil != &int(0)`}},
{struct{ x *int }{&i0}, struct{ x *int }{nil}, []string{`x: &int(0) != nil`}},
{struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{0}}, nil},
{struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{1}}, []string{`x[0]: 0 != 1`}},
{struct{ x string }{"a"}, struct{ x string }{"a"}, nil},
{struct{ x string }{"a"}, struct{ x string }{"b"}, []string{`x: "a" != "b"`}},
{struct{ x N }{N{0}}, struct{ x N }{N{0}}, nil},
{struct{ x N }{N{0}}, struct{ x N }{N{1}}, []string{`x.N: 0 != 1`}},
{
struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
nil,
},
{
struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))},
struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(1))},
[]string{`x: 0x0 != 0x1`},
},
}
func TestDiff(t *testing.T) {
for _, tt := range diffs {
got := Diff(tt.a, tt.b)
eq := len(got) == len(tt.exp)
if eq {
for i := range got {
eq = eq && got[i] == tt.exp[i]
}
}
if !eq {
t.Errorf("diffing % #v", tt.a)
t.Errorf("with % #v", tt.b)
diffdiff(t, got, tt.exp)
continue
}
}
}
func TestKeyEqual(t *testing.T) {
var emptyInterfaceZero interface{} = 0
cases := []interface{}{
new(bool),
new(int),
new(int8),
new(int16),
new(int32),
new(int64),
new(uint),
new(uint8),
new(uint16),
new(uint32),
new(uint64),
new(uintptr),
new(float32),
new(float64),
new(complex64),
new(complex128),
new([1]int),
new(chan int),
new(unsafe.Pointer),
new(interface{}),
&emptyInterfaceZero,
new(*int),
new(string),
new(struct{ int }),
}
for _, test := range cases {
rv := reflect.ValueOf(test).Elem()
if !keyEqual(rv, rv) {
t.Errorf("keyEqual(%s, %s) = false want true", rv.Type(), rv.Type())
}
}
}
func TestFdiff(t *testing.T) {
var buf bytes.Buffer
Fdiff(&buf, 0, 1)
want := "0 != 1\n"
if got := buf.String(); got != want {
t.Errorf("Fdiff(0, 1) = %q want %q", got, want)
}
}
func diffdiff(t *testing.T, got, exp []string) {
minus(t, "unexpected:", got, exp)
minus(t, "missing:", exp, got)
}
func minus(t *testing.T, s string, a, b []string) {
var i, j int
for i = 0; i < len(a); i++ {
for j = 0; j < len(b); j++ {
if a[i] == b[j] {
break
}
}
if j == len(b) {
t.Error(s, a[i])
}
}
}

20
vendor/github.com/kr/pretty/example_test.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
package pretty_test
import (
"fmt"
"github.com/kr/pretty"
)
func Example() {
type myType struct {
a, b int
}
var x = []myType{{1, 2}, {3, 4}, {5, 6}}
fmt.Printf("%# v", pretty.Formatter(x))
// output:
// []pretty_test.myType{
// {a:1, b:2},
// {a:3, b:4},
// {a:5, b:6},
// }
}

328
vendor/github.com/kr/pretty/formatter.go generated vendored Normal file
View File

@ -0,0 +1,328 @@
package pretty
import (
"fmt"
"io"
"reflect"
"strconv"
"text/tabwriter"
"github.com/kr/text"
)
type formatter struct {
v reflect.Value
force bool
quote bool
}
// Formatter makes a wrapper, f, that will format x as go source with line
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
// "#" and " " (space) flags are set, for example:
//
// fmt.Sprintf("%# v", Formatter(x))
//
// If one of these two flags is not set, or any other verb is used, f will
// format x according to the usual rules of package fmt.
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
func Formatter(x interface{}) (f fmt.Formatter) {
return formatter{v: reflect.ValueOf(x), quote: true}
}
func (fo formatter) String() string {
return fmt.Sprint(fo.v.Interface()) // unwrap it
}
func (fo formatter) passThrough(f fmt.State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
s += string(i)
}
}
if w, ok := f.Width(); ok {
s += fmt.Sprintf("%d", w)
}
if p, ok := f.Precision(); ok {
s += fmt.Sprintf(".%d", p)
}
s += string(c)
fmt.Fprintf(f, s, fo.v.Interface())
}
func (fo formatter) Format(f fmt.State, c rune) {
if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') {
w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0)
p := &printer{tw: w, Writer: w, visited: make(map[visit]int)}
p.printValue(fo.v, true, fo.quote)
w.Flush()
return
}
fo.passThrough(f, c)
}
type printer struct {
io.Writer
tw *tabwriter.Writer
visited map[visit]int
depth int
}
func (p *printer) indent() *printer {
q := *p
q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0)
q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'})
return &q
}
func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) {
if showType {
io.WriteString(p, v.Type().String())
fmt.Fprintf(p, "(%#v)", x)
} else {
fmt.Fprintf(p, "%#v", x)
}
}
// printValue must keep track of already-printed pointer values to avoid
// infinite recursion.
type visit struct {
v uintptr
typ reflect.Type
}
func (p *printer) printValue(v reflect.Value, showType, quote bool) {
if p.depth > 10 {
io.WriteString(p, "!%v(DEPTH EXCEEDED)")
return
}
switch v.Kind() {
case reflect.Bool:
p.printInline(v, v.Bool(), showType)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p.printInline(v, v.Int(), showType)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p.printInline(v, v.Uint(), showType)
case reflect.Float32, reflect.Float64:
p.printInline(v, v.Float(), showType)
case reflect.Complex64, reflect.Complex128:
fmt.Fprintf(p, "%#v", v.Complex())
case reflect.String:
p.fmtString(v.String(), quote)
case reflect.Map:
t := v.Type()
if showType {
io.WriteString(p, t.String())
}
writeByte(p, '{')
if nonzero(v) {
expand := !canInline(v.Type())
pp := p
if expand {
writeByte(p, '\n')
pp = p.indent()
}
keys := v.MapKeys()
for i := 0; i < v.Len(); i++ {
showTypeInStruct := true
k := keys[i]
mv := v.MapIndex(k)
pp.printValue(k, false, true)
writeByte(pp, ':')
if expand {
writeByte(pp, '\t')
}
showTypeInStruct = t.Elem().Kind() == reflect.Interface
pp.printValue(mv, showTypeInStruct, true)
if expand {
io.WriteString(pp, ",\n")
} else if i < v.Len()-1 {
io.WriteString(pp, ", ")
}
}
if expand {
pp.tw.Flush()
}
}
writeByte(p, '}')
case reflect.Struct:
t := v.Type()
if v.CanAddr() {
addr := v.UnsafeAddr()
vis := visit{addr, t}
if vd, ok := p.visited[vis]; ok && vd < p.depth {
p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false)
break // don't print v again
}
p.visited[vis] = p.depth
}
if showType {
io.WriteString(p, t.String())
}
writeByte(p, '{')
if nonzero(v) {
expand := !canInline(v.Type())
pp := p
if expand {
writeByte(p, '\n')
pp = p.indent()
}
for i := 0; i < v.NumField(); i++ {
showTypeInStruct := true
if f := t.Field(i); f.Name != "" {
io.WriteString(pp, f.Name)
writeByte(pp, ':')
if expand {
writeByte(pp, '\t')
}
showTypeInStruct = labelType(f.Type)
}
pp.printValue(getField(v, i), showTypeInStruct, true)
if expand {
io.WriteString(pp, ",\n")
} else if i < v.NumField()-1 {
io.WriteString(pp, ", ")
}
}
if expand {
pp.tw.Flush()
}
}
writeByte(p, '}')
case reflect.Interface:
switch e := v.Elem(); {
case e.Kind() == reflect.Invalid:
io.WriteString(p, "nil")
case e.IsValid():
pp := *p
pp.depth++
pp.printValue(e, showType, true)
default:
io.WriteString(p, v.Type().String())
io.WriteString(p, "(nil)")
}
case reflect.Array, reflect.Slice:
t := v.Type()
if showType {
io.WriteString(p, t.String())
}
if v.Kind() == reflect.Slice && v.IsNil() && showType {
io.WriteString(p, "(nil)")
break
}
if v.Kind() == reflect.Slice && v.IsNil() {
io.WriteString(p, "nil")
break
}
writeByte(p, '{')
expand := !canInline(v.Type())
pp := p
if expand {
writeByte(p, '\n')
pp = p.indent()
}
for i := 0; i < v.Len(); i++ {
showTypeInSlice := t.Elem().Kind() == reflect.Interface
pp.printValue(v.Index(i), showTypeInSlice, true)
if expand {
io.WriteString(pp, ",\n")
} else if i < v.Len()-1 {
io.WriteString(pp, ", ")
}
}
if expand {
pp.tw.Flush()
}
writeByte(p, '}')
case reflect.Ptr:
e := v.Elem()
if !e.IsValid() {
writeByte(p, '(')
io.WriteString(p, v.Type().String())
io.WriteString(p, ")(nil)")
} else {
pp := *p
pp.depth++
writeByte(pp, '&')
pp.printValue(e, true, true)
}
case reflect.Chan:
x := v.Pointer()
if showType {
writeByte(p, '(')
io.WriteString(p, v.Type().String())
fmt.Fprintf(p, ")(%#v)", x)
} else {
fmt.Fprintf(p, "%#v", x)
}
case reflect.Func:
io.WriteString(p, v.Type().String())
io.WriteString(p, " {...}")
case reflect.UnsafePointer:
p.printInline(v, v.Pointer(), showType)
case reflect.Invalid:
io.WriteString(p, "nil")
}
}
func canInline(t reflect.Type) bool {
switch t.Kind() {
case reflect.Map:
return !canExpand(t.Elem())
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
if canExpand(t.Field(i).Type) {
return false
}
}
return true
case reflect.Interface:
return false
case reflect.Array, reflect.Slice:
return !canExpand(t.Elem())
case reflect.Ptr:
return false
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
return false
}
return true
}
func canExpand(t reflect.Type) bool {
switch t.Kind() {
case reflect.Map, reflect.Struct,
reflect.Interface, reflect.Array, reflect.Slice,
reflect.Ptr:
return true
}
return false
}
func labelType(t reflect.Type) bool {
switch t.Kind() {
case reflect.Interface, reflect.Struct:
return true
}
return false
}
func (p *printer) fmtString(s string, quote bool) {
if quote {
s = strconv.Quote(s)
}
io.WriteString(p, s)
}
func writeByte(w io.Writer, b byte) {
w.Write([]byte{b})
}
func getField(v reflect.Value, i int) reflect.Value {
val := v.Field(i)
if val.Kind() == reflect.Interface && !val.IsNil() {
val = val.Elem()
}
return val
}

288
vendor/github.com/kr/pretty/formatter_test.go generated vendored Normal file
View File

@ -0,0 +1,288 @@
package pretty
import (
"fmt"
"io"
"strings"
"testing"
"unsafe"
)
type test struct {
v interface{}
s string
}
type passtest struct {
v interface{}
f, s string
}
type LongStructTypeName struct {
longFieldName interface{}
otherLongFieldName interface{}
}
type SA struct {
t *T
v T
}
type T struct {
x, y int
}
type F int
func (f F) Format(s fmt.State, c rune) {
fmt.Fprintf(s, "F(%d)", int(f))
}
type Stringer struct { i int }
func (s *Stringer) String() string { return "foo" }
var long = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var passthrough = []passtest{
{1, "%d", "1"},
{"a", "%s", "a"},
{&Stringer{}, "%s", "foo"},
}
func TestPassthrough(t *testing.T) {
for _, tt := range passthrough {
s := fmt.Sprintf(tt.f, Formatter(tt.v))
if tt.s != s {
t.Errorf("expected %q", tt.s)
t.Errorf("got %q", s)
t.Errorf("expraw\n%s", tt.s)
t.Errorf("gotraw\n%s", s)
}
}
}
var gosyntax = []test{
{nil, `nil`},
{"", `""`},
{"a", `"a"`},
{1, "int(1)"},
{1.0, "float64(1)"},
{[]int(nil), "[]int(nil)"},
{[0]int{}, "[0]int{}"},
{complex(1, 0), "(1+0i)"},
//{make(chan int), "(chan int)(0x1234)"},
{unsafe.Pointer(uintptr(unsafe.Pointer(&long))), fmt.Sprintf("unsafe.Pointer(0x%02x)", uintptr(unsafe.Pointer(&long)))},
{func(int) {}, "func(int) {...}"},
{map[int]int{1: 1}, "map[int]int{1:1}"},
{int32(1), "int32(1)"},
{io.EOF, `&errors.errorString{s:"EOF"}`},
{[]string{"a"}, `[]string{"a"}`},
{
[]string{long},
`[]string{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"}`,
},
{F(5), "pretty.F(5)"},
{
SA{&T{1, 2}, T{3, 4}},
`pretty.SA{
t: &pretty.T{x:1, y:2},
v: pretty.T{x:3, y:4},
}`,
},
{
map[int][]byte{1: {}},
`map[int][]uint8{
1: {},
}`,
},
{
map[int]T{1: {}},
`map[int]pretty.T{
1: {},
}`,
},
{
long,
`"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"`,
},
{
LongStructTypeName{
longFieldName: LongStructTypeName{},
otherLongFieldName: long,
},
`pretty.LongStructTypeName{
longFieldName: pretty.LongStructTypeName{},
otherLongFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
}`,
},
{
&LongStructTypeName{
longFieldName: &LongStructTypeName{},
otherLongFieldName: (*LongStructTypeName)(nil),
},
`&pretty.LongStructTypeName{
longFieldName: &pretty.LongStructTypeName{},
otherLongFieldName: (*pretty.LongStructTypeName)(nil),
}`,
},
{
[]LongStructTypeName{
{nil, nil},
{3, 3},
{long, nil},
},
`[]pretty.LongStructTypeName{
{},
{
longFieldName: int(3),
otherLongFieldName: int(3),
},
{
longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
otherLongFieldName: nil,
},
}`,
},
{
[]interface{}{
LongStructTypeName{nil, nil},
[]byte{1, 2, 3},
T{3, 4},
LongStructTypeName{long, nil},
},
`[]interface {}{
pretty.LongStructTypeName{},
[]uint8{0x1, 0x2, 0x3},
pretty.T{x:3, y:4},
pretty.LongStructTypeName{
longFieldName: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
otherLongFieldName: nil,
},
}`,
},
}
func TestGoSyntax(t *testing.T) {
for _, tt := range gosyntax {
s := fmt.Sprintf("%# v", Formatter(tt.v))
if tt.s != s {
t.Errorf("expected %q", tt.s)
t.Errorf("got %q", s)
t.Errorf("expraw\n%s", tt.s)
t.Errorf("gotraw\n%s", s)
}
}
}
type I struct {
i int
R interface{}
}
func (i *I) I() *I { return i.R.(*I) }
func TestCycle(t *testing.T) {
type A struct{ *A }
v := &A{}
v.A = v
// panics from stack overflow without cycle detection
t.Logf("Example cycle:\n%# v", Formatter(v))
p := &A{}
s := fmt.Sprintf("%# v", Formatter([]*A{p, p}))
if strings.Contains(s, "CYCLIC") {
t.Errorf("Repeated address detected as cyclic reference:\n%s", s)
}
type R struct {
i int
*R
}
r := &R{
i: 1,
R: &R{
i: 2,
R: &R{
i: 3,
},
},
}
r.R.R.R = r
t.Logf("Example longer cycle:\n%# v", Formatter(r))
r = &R{
i: 1,
R: &R{
i: 2,
R: &R{
i: 3,
R: &R{
i: 4,
R: &R{
i: 5,
R: &R{
i: 6,
R: &R{
i: 7,
R: &R{
i: 8,
R: &R{
i: 9,
R: &R{
i: 10,
R: &R{
i: 11,
},
},
},
},
},
},
},
},
},
},
}
// here be pirates
r.R.R.R.R.R.R.R.R.R.R.R = r
t.Logf("Example very long cycle:\n%# v", Formatter(r))
i := &I{
i: 1,
R: &I{
i: 2,
R: &I{
i: 3,
R: &I{
i: 4,
R: &I{
i: 5,
R: &I{
i: 6,
R: &I{
i: 7,
R: &I{
i: 8,
R: &I{
i: 9,
R: &I{
i: 10,
R: &I{
i: 11,
},
},
},
},
},
},
},
},
},
},
}
iv := i.I().I().I().I().I().I().I().I().I().I()
*iv = *i
t.Logf("Example long interface cycle:\n%# v", Formatter(i))
}

3
vendor/github.com/kr/pretty/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module "github.com/kr/pretty"
require "github.com/kr/text" v0.1.0

108
vendor/github.com/kr/pretty/pretty.go generated vendored Normal file
View File

@ -0,0 +1,108 @@
// Package pretty provides pretty-printing for Go values. This is
// useful during debugging, to avoid wrapping long output lines in
// the terminal.
//
// It provides a function, Formatter, that can be used with any
// function that accepts a format string. It also provides
// convenience wrappers for functions in packages fmt and log.
package pretty
import (
"fmt"
"io"
"log"
"reflect"
)
// Errorf is a convenience wrapper for fmt.Errorf.
//
// Calling Errorf(f, x, y) is equivalent to
// fmt.Errorf(f, Formatter(x), Formatter(y)).
func Errorf(format string, a ...interface{}) error {
return fmt.Errorf(format, wrap(a, false)...)
}
// Fprintf is a convenience wrapper for fmt.Fprintf.
//
// Calling Fprintf(w, f, x, y) is equivalent to
// fmt.Fprintf(w, f, Formatter(x), Formatter(y)).
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error error) {
return fmt.Fprintf(w, format, wrap(a, false)...)
}
// Log is a convenience wrapper for log.Printf.
//
// Calling Log(x, y) is equivalent to
// log.Print(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Log(a ...interface{}) {
log.Print(wrap(a, true)...)
}
// Logf is a convenience wrapper for log.Printf.
//
// Calling Logf(f, x, y) is equivalent to
// log.Printf(f, Formatter(x), Formatter(y)).
func Logf(format string, a ...interface{}) {
log.Printf(format, wrap(a, false)...)
}
// Logln is a convenience wrapper for log.Printf.
//
// Calling Logln(x, y) is equivalent to
// log.Println(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Logln(a ...interface{}) {
log.Println(wrap(a, true)...)
}
// Print pretty-prints its operands and writes to standard output.
//
// Calling Print(x, y) is equivalent to
// fmt.Print(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Print(a ...interface{}) (n int, errno error) {
return fmt.Print(wrap(a, true)...)
}
// Printf is a convenience wrapper for fmt.Printf.
//
// Calling Printf(f, x, y) is equivalent to
// fmt.Printf(f, Formatter(x), Formatter(y)).
func Printf(format string, a ...interface{}) (n int, errno error) {
return fmt.Printf(format, wrap(a, false)...)
}
// Println pretty-prints its operands and writes to standard output.
//
// Calling Print(x, y) is equivalent to
// fmt.Println(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Println(a ...interface{}) (n int, errno error) {
return fmt.Println(wrap(a, true)...)
}
// Sprint is a convenience wrapper for fmt.Sprintf.
//
// Calling Sprint(x, y) is equivalent to
// fmt.Sprint(Formatter(x), Formatter(y)), but each operand is
// formatted with "%# v".
func Sprint(a ...interface{}) string {
return fmt.Sprint(wrap(a, true)...)
}
// Sprintf is a convenience wrapper for fmt.Sprintf.
//
// Calling Sprintf(f, x, y) is equivalent to
// fmt.Sprintf(f, Formatter(x), Formatter(y)).
func Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, wrap(a, false)...)
}
func wrap(a []interface{}, force bool) []interface{} {
w := make([]interface{}, len(a))
for i, x := range a {
w[i] = formatter{v: reflect.ValueOf(x), force: force}
}
return w
}

41
vendor/github.com/kr/pretty/zero.go generated vendored Normal file
View File

@ -0,0 +1,41 @@
package pretty
import (
"reflect"
)
func nonzero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() != 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() != 0
case reflect.Float32, reflect.Float64:
return v.Float() != 0
case reflect.Complex64, reflect.Complex128:
return v.Complex() != complex(0, 0)
case reflect.String:
return v.String() != ""
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
if nonzero(getField(v, i)) {
return true
}
}
return false
case reflect.Array:
for i := 0; i < v.Len(); i++ {
if nonzero(v.Index(i)) {
return true
}
}
return false
case reflect.Map, reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Chan, reflect.Func:
return !v.IsNil()
case reflect.UnsafePointer:
return v.Pointer() != 0
}
return true
}

19
vendor/github.com/kr/text/License generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright 2012 Keith Rarick
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.

3
vendor/github.com/kr/text/Readme generated vendored Normal file
View File

@ -0,0 +1,3 @@
This is a Go package for manipulating paragraphs of text.
See http://go.pkgdoc.org/github.com/kr/text for full documentation.

3
vendor/github.com/kr/text/doc.go generated vendored Normal file
View File

@ -0,0 +1,3 @@
// Package text provides rudimentary functions for manipulating text in
// paragraphs.
package text

3
vendor/github.com/kr/text/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module "github.com/kr/text"
require "github.com/kr/pty" v1.1.1

74
vendor/github.com/kr/text/indent.go generated vendored Normal file
View File

@ -0,0 +1,74 @@
package text
import (
"io"
)
// Indent inserts prefix at the beginning of each non-empty line of s. The
// end-of-line marker is NL.
func Indent(s, prefix string) string {
return string(IndentBytes([]byte(s), []byte(prefix)))
}
// IndentBytes inserts prefix at the beginning of each non-empty line of b.
// The end-of-line marker is NL.
func IndentBytes(b, prefix []byte) []byte {
var res []byte
bol := true
for _, c := range b {
if bol && c != '\n' {
res = append(res, prefix...)
}
res = append(res, c)
bol = c == '\n'
}
return res
}
// Writer indents each line of its input.
type indentWriter struct {
w io.Writer
bol bool
pre [][]byte
sel int
off int
}
// NewIndentWriter makes a new write filter that indents the input
// lines. Each line is prefixed in order with the corresponding
// element of pre. If there are more lines than elements, the last
// element of pre is repeated for each subsequent line.
func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer {
return &indentWriter{
w: w,
pre: pre,
bol: true,
}
}
// The only errors returned are from the underlying indentWriter.
func (w *indentWriter) Write(p []byte) (n int, err error) {
for _, c := range p {
if w.bol {
var i int
i, err = w.w.Write(w.pre[w.sel][w.off:])
w.off += i
if err != nil {
return n, err
}
}
_, err = w.w.Write([]byte{c})
if err != nil {
return n, err
}
n++
w.bol = c == '\n'
if w.bol {
w.off = 0
if w.sel < len(w.pre)-1 {
w.sel++
}
}
}
return n, nil
}

119
vendor/github.com/kr/text/indent_test.go generated vendored Normal file
View File

@ -0,0 +1,119 @@
package text
import (
"bytes"
"testing"
)
type T struct {
inp, exp, pre string
}
var tests = []T{
{
"The quick brown fox\njumps over the lazy\ndog.\nBut not quickly.\n",
"xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\nxxxBut not quickly.\n",
"xxx",
},
{
"The quick brown fox\njumps over the lazy\ndog.\n\nBut not quickly.",
"xxxThe quick brown fox\nxxxjumps over the lazy\nxxxdog.\n\nxxxBut not quickly.",
"xxx",
},
}
func TestIndent(t *testing.T) {
for _, test := range tests {
got := Indent(test.inp, test.pre)
if got != test.exp {
t.Errorf("mismatch %q != %q", got, test.exp)
}
}
}
type IndentWriterTest struct {
inp, exp string
pre []string
}
var ts = []IndentWriterTest{
{
`
The quick brown fox
jumps over the lazy
dog.
But not quickly.
`[1:],
`
xxxThe quick brown fox
xxxjumps over the lazy
xxxdog.
xxxBut not quickly.
`[1:],
[]string{"xxx"},
},
{
`
The quick brown fox
jumps over the lazy
dog.
But not quickly.
`[1:],
`
xxaThe quick brown fox
xxxjumps over the lazy
xxxdog.
xxxBut not quickly.
`[1:],
[]string{"xxa", "xxx"},
},
{
`
The quick brown fox
jumps over the lazy
dog.
But not quickly.
`[1:],
`
xxaThe quick brown fox
xxbjumps over the lazy
xxcdog.
xxxBut not quickly.
`[1:],
[]string{"xxa", "xxb", "xxc", "xxx"},
},
{
`
The quick brown fox
jumps over the lazy
dog.
But not quickly.`[1:],
`
xxaThe quick brown fox
xxxjumps over the lazy
xxxdog.
xxx
xxxBut not quickly.`[1:],
[]string{"xxa", "xxx"},
},
}
func TestIndentWriter(t *testing.T) {
for _, test := range ts {
b := new(bytes.Buffer)
pre := make([][]byte, len(test.pre))
for i := range test.pre {
pre[i] = []byte(test.pre[i])
}
w := NewIndentWriter(b, pre...)
if _, err := w.Write([]byte(test.inp)); err != nil {
t.Error(err)
}
if got := b.String(); got != test.exp {
t.Errorf("mismatch %q != %q", got, test.exp)
t.Log(got)
t.Log(test.exp)
}
}
}

86
vendor/github.com/kr/text/wrap.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
package text
import (
"bytes"
"math"
)
var (
nl = []byte{'\n'}
sp = []byte{' '}
)
const defaultPenalty = 1e5
// Wrap wraps s into a paragraph of lines of length lim, with minimal
// raggedness.
func Wrap(s string, lim int) string {
return string(WrapBytes([]byte(s), lim))
}
// WrapBytes wraps b into a paragraph of lines of length lim, with minimal
// raggedness.
func WrapBytes(b []byte, lim int) []byte {
words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp)
var lines [][]byte
for _, line := range WrapWords(words, 1, lim, defaultPenalty) {
lines = append(lines, bytes.Join(line, sp))
}
return bytes.Join(lines, nl)
}
// WrapWords is the low-level line-breaking algorithm, useful if you need more
// control over the details of the text wrapping process. For most uses, either
// Wrap or WrapBytes will be sufficient and more convenient.
//
// WrapWords splits a list of words into lines with minimal "raggedness",
// treating each byte as one unit, accounting for spc units between adjacent
// words on each line, and attempting to limit lines to lim units. Raggedness
// is the total error over all lines, where error is the square of the
// difference of the length of the line and lim. Too-long lines (which only
// happen when a single word is longer than lim units) have pen penalty units
// added to the error.
func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte {
n := len(words)
length := make([][]int, n)
for i := 0; i < n; i++ {
length[i] = make([]int, n)
length[i][i] = len(words[i])
for j := i + 1; j < n; j++ {
length[i][j] = length[i][j-1] + spc + len(words[j])
}
}
nbrk := make([]int, n)
cost := make([]int, n)
for i := range cost {
cost[i] = math.MaxInt32
}
for i := n - 1; i >= 0; i-- {
if length[i][n-1] <= lim || i == n-1 {
cost[i] = 0
nbrk[i] = n
} else {
for j := i + 1; j < n; j++ {
d := lim - length[i][j-1]
c := d*d + cost[j]
if length[i][j-1] > lim {
c += pen // too-long lines get a worse penalty
}
if c < cost[i] {
cost[i] = c
nbrk[i] = j
}
}
}
}
var lines [][][]byte
i := 0
for i < n {
lines = append(lines, words[i:nbrk[i]])
i = nbrk[i]
}
return lines
}

62
vendor/github.com/kr/text/wrap_test.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
package text
import (
"bytes"
"testing"
)
var text = "The quick brown fox jumps over the lazy dog."
func TestWrap(t *testing.T) {
exp := [][]string{
{"The", "quick", "brown", "fox"},
{"jumps", "over", "the", "lazy", "dog."},
}
words := bytes.Split([]byte(text), sp)
got := WrapWords(words, 1, 24, defaultPenalty)
if len(exp) != len(got) {
t.Fail()
}
for i := range exp {
if len(exp[i]) != len(got[i]) {
t.Fail()
}
for j := range exp[i] {
if exp[i][j] != string(got[i][j]) {
t.Fatal(i, exp[i][j], got[i][j])
}
}
}
}
func TestWrapNarrow(t *testing.T) {
exp := "The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog."
if Wrap(text, 5) != exp {
t.Fail()
}
}
func TestWrapOneLine(t *testing.T) {
exp := "The quick brown fox jumps over the lazy dog."
if Wrap(text, 500) != exp {
t.Fail()
}
}
func TestWrapBug1(t *testing.T) {
cases := []struct {
limit int
text string
want string
}{
{4, "aaaaa", "aaaaa"},
{4, "a aaaaa", "a\naaaaa"},
}
for _, test := range cases {
got := Wrap(test.text, test.limit)
if got != test.want {
t.Errorf("Wrap(%q, %d) = %q want %q", test.text, test.limit, got, test.want)
}
}
}

View File

@ -23,6 +23,12 @@ func (b *Builder) AddASN1Int64(v int64) {
b.addASN1Signed(asn1.INTEGER, v) b.addASN1Signed(asn1.INTEGER, v)
} }
// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the
// given tag.
func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) {
b.addASN1Signed(tag, v)
}
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION. // AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
func (b *Builder) AddASN1Enum(v int64) { func (b *Builder) AddASN1Enum(v int64) {
b.addASN1Signed(asn1.ENUM, v) b.addASN1Signed(asn1.ENUM, v)
@ -224,6 +230,9 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
// String // String
// ReadASN1Boolean decodes an ASN.1 INTEGER and converts it to a boolean
// representation into out and advances. It reports whether the read
// was successful.
func (s *String) ReadASN1Boolean(out *bool) bool { func (s *String) ReadASN1Boolean(out *bool) bool {
var bytes String var bytes String
if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 { if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 {
@ -245,8 +254,8 @@ func (s *String) ReadASN1Boolean(out *bool) bool {
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem() var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does // 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 // not point to an integer or to a big.Int, it panics. It reports whether the
// success and false on error. // read was successful.
func (s *String) ReadASN1Integer(out interface{}) bool { func (s *String) ReadASN1Integer(out interface{}) bool {
if reflect.TypeOf(out).Kind() != reflect.Ptr { if reflect.TypeOf(out).Kind() != reflect.Ptr {
panic("out is not a pointer") panic("out is not a pointer")
@ -359,8 +368,16 @@ func asn1Unsigned(out *uint64, n []byte) bool {
return true return true
} }
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns // ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out
// true on success and false on error. // and advances. It reports whether the read was successful and resulted in a
// value that can be represented in an int64.
func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool {
var bytes String
return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes)
}
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports
// whether the read was successful.
func (s *String) ReadASN1Enum(out *int) bool { func (s *String) ReadASN1Enum(out *int) bool {
var bytes String var bytes String
var i int64 var i int64
@ -392,7 +409,7 @@ func (s *String) readBase128Int(out *int) bool {
} }
// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and // ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
// advances. It returns true on success and false on error. // advances. It reports whether the read was successful.
func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool { func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool {
var bytes String var bytes String
if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 { if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 {
@ -431,7 +448,7 @@ func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) b
} }
// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and // ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
// advances. It returns true on success and false on error. // advances. It reports whether the read was successful.
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool { func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
var bytes String var bytes String
if !s.ReadASN1(&bytes, asn1.GeneralizedTime) { if !s.ReadASN1(&bytes, asn1.GeneralizedTime) {
@ -449,8 +466,8 @@ func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
return true return true
} }
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It // ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances.
// returns true on success and false on error. // It reports whether the read was successful.
func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
var bytes String var bytes String
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 { if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
@ -471,8 +488,8 @@ func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
} }
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is // ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is
// an error if the BIT STRING is not a whole number of bytes. This function // an error if the BIT STRING is not a whole number of bytes. It reports
// returns true on success and false on error. // whether the read was successful.
func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool { func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
var bytes String var bytes String
if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 { if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 {
@ -489,14 +506,14 @@ func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
// ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including // 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 // tag and length bytes) into out, and advances. The element must match the
// given tag. It returns true on success and false on error. // given tag. It reports whether the read was successful.
func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool { func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool {
return s.ReadASN1((*String)(out), tag) return s.ReadASN1((*String)(out), tag)
} }
// ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including // 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 // tag and length bytes) into out, and advances. The element must match the
// given tag. It returns true on success and false on error. // given tag. It reports whether the read was successful.
// //
// Tags greater than 30 are not supported (i.e. low-tag-number format only). // Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadASN1(out *String, tag asn1.Tag) bool { func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
@ -509,7 +526,7 @@ func (s *String) ReadASN1(out *String, tag asn1.Tag) bool {
// ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including // 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 // tag and length bytes) into out, and advances. The element must match the
// given tag. It returns true on success and false on error. // given tag. It reports whether the read was successful.
// //
// Tags greater than 30 are not supported (i.e. low-tag-number format only). // Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool { func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
@ -521,8 +538,8 @@ func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool {
} }
// ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including // 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 // tag and length bytes) into out, sets outTag to its tag, and advances.
// returns true on success and false on error. // It reports whether the read was successful.
// //
// Tags greater than 30 are not supported (i.e. low-tag-number format only). // Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool { func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
@ -531,14 +548,14 @@ func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool {
// ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element // ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element
// (including tag and length bytes) into out, sets outTag to is tag, and // (including tag and length bytes) into out, sets outTag to is tag, and
// advances. It returns true on success and false on error. // advances. It reports whether the read was successful.
// //
// Tags greater than 30 are not supported (i.e. low-tag-number format only). // Tags greater than 30 are not supported (i.e. low-tag-number format only).
func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool { func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool {
return s.readASN1(out, outTag, false /* include header */) return s.readASN1(out, outTag, false /* include header */)
} }
// PeekASN1Tag returns true if the next ASN.1 value on the string starts with // PeekASN1Tag reports whether the next ASN.1 value on the string starts with
// the given tag. // the given tag.
func (s String) PeekASN1Tag(tag asn1.Tag) bool { func (s String) PeekASN1Tag(tag asn1.Tag) bool {
if len(s) == 0 { if len(s) == 0 {
@ -547,7 +564,8 @@ func (s String) PeekASN1Tag(tag asn1.Tag) bool {
return asn1.Tag(s[0]) == tag return asn1.Tag(s[0]) == tag
} }
// SkipASN1 reads and discards an ASN.1 element with the given tag. // SkipASN1 reads and discards an ASN.1 element with the given tag. It
// reports whether the operation was successful.
func (s *String) SkipASN1(tag asn1.Tag) bool { func (s *String) SkipASN1(tag asn1.Tag) bool {
var unused String var unused String
return s.ReadASN1(&unused, tag) return s.ReadASN1(&unused, tag)
@ -556,7 +574,7 @@ func (s *String) SkipASN1(tag asn1.Tag) bool {
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1 // ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1
// element (not including tag and length bytes) tagged with the given tag into // 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, // out. It stores whether an element with the tag was found in outPresent,
// unless outPresent is nil. It returns true on success and false on error. // unless outPresent is nil. It reports whether the read was successful.
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool { func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool {
present := s.PeekASN1Tag(tag) present := s.PeekASN1Tag(tag)
if outPresent != nil { if outPresent != nil {
@ -569,7 +587,7 @@ func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) b
} }
// SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or // SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or
// else leaves s unchanged. // else leaves s unchanged. It reports whether the operation was successful.
func (s *String) SkipOptionalASN1(tag asn1.Tag) bool { func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
if !s.PeekASN1Tag(tag) { if !s.PeekASN1Tag(tag) {
return true return true
@ -581,8 +599,8 @@ func (s *String) SkipOptionalASN1(tag asn1.Tag) bool {
// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER // ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER
// explicitly tagged with tag into out and advances. If no element with a // 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 // 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 // does not point to an integer or to a big.Int, it panics. It reports
// success and false on error. // whether the read was successful.
func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool { func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool {
if reflect.TypeOf(out).Kind() != reflect.Ptr { if reflect.TypeOf(out).Kind() != reflect.Ptr {
panic("out is not a pointer") panic("out is not a pointer")
@ -619,8 +637,8 @@ func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultV
// ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING // ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING
// explicitly tagged with tag into out and advances. If no element with a // 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 // matching tag is present, it sets "out" to nil instead. It reports
// true on success and false on error. // whether the read was successful.
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.Tag) bool { func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.Tag) bool {
var present bool var present bool
var child String var child String
@ -644,6 +662,7 @@ func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag
// ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or, // ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or,
// if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue. // if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue.
// It reports whether the operation was successful.
func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool { func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool {
var present bool var present bool
var child String var child String

View File

@ -149,6 +149,39 @@ func TestReadASN1IntegerSigned(t *testing.T) {
} }
} }
}) })
// Repeat with the implicit-tagging functions
t.Run("WithTag", func(t *testing.T) {
for i, test := range testData64 {
tag := asn1.Tag((i * 3) % 32).ContextSpecific()
testData := make([]byte, len(test.in))
copy(testData, test.in)
// Alter the tag of the test case.
testData[0] = uint8(tag)
in := String(testData)
var out int64
ok := in.ReadASN1Int64WithTag(&out, tag)
if !ok || out != test.out {
t.Errorf("#%d: in.ReadASN1Int64WithTag() = %v, want true; out = %d, want %d", i, ok, out, test.out)
}
var b Builder
b.AddASN1Int64WithTag(test.out, tag)
result, err := b.Bytes()
if err != nil {
t.Errorf("#%d: AddASN1Int64WithTag failed: %s", i, err)
continue
}
if !bytes.Equal(result, testData) {
t.Errorf("#%d: AddASN1Int64WithTag: got %x, want %x", i, result, testData)
}
}
})
} }
func TestReadASN1IntegerUnsigned(t *testing.T) { func TestReadASN1IntegerUnsigned(t *testing.T) {

View File

@ -37,8 +37,8 @@ func (s *String) Skip(n int) bool {
return s.read(n) != nil return s.read(n) != nil
} }
// ReadUint8 decodes an 8-bit value into out and advances over it. It // ReadUint8 decodes an 8-bit value into out and advances over it.
// returns true on success and false on error. // It reports whether the read was successful.
func (s *String) ReadUint8(out *uint8) bool { func (s *String) ReadUint8(out *uint8) bool {
v := s.read(1) v := s.read(1)
if v == nil { if v == nil {
@ -49,7 +49,7 @@ func (s *String) ReadUint8(out *uint8) bool {
} }
// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it. // ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
// It returns true on success and false on error. // It reports whether the read was successful.
func (s *String) ReadUint16(out *uint16) bool { func (s *String) ReadUint16(out *uint16) bool {
v := s.read(2) v := s.read(2)
if v == nil { if v == nil {
@ -60,7 +60,7 @@ func (s *String) ReadUint16(out *uint16) bool {
} }
// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it. // ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
// It returns true on success and false on error. // It reports whether the read was successful.
func (s *String) ReadUint24(out *uint32) bool { func (s *String) ReadUint24(out *uint32) bool {
v := s.read(3) v := s.read(3)
if v == nil { if v == nil {
@ -71,7 +71,7 @@ func (s *String) ReadUint24(out *uint32) bool {
} }
// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it. // ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
// It returns true on success and false on error. // It reports whether the read was successful.
func (s *String) ReadUint32(out *uint32) bool { func (s *String) ReadUint32(out *uint32) bool {
v := s.read(4) v := s.read(4)
if v == nil { if v == nil {
@ -119,28 +119,27 @@ func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
} }
// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value // 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 // into out and advances over it. It reports whether the read was successful.
// error.
func (s *String) ReadUint8LengthPrefixed(out *String) bool { func (s *String) ReadUint8LengthPrefixed(out *String) bool {
return s.readLengthPrefixed(1, out) return s.readLengthPrefixed(1, out)
} }
// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit // ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
// length-prefixed value into out and advances over it. It returns true on // length-prefixed value into out and advances over it. It reports whether the
// success and false on error. // read was successful.
func (s *String) ReadUint16LengthPrefixed(out *String) bool { func (s *String) ReadUint16LengthPrefixed(out *String) bool {
return s.readLengthPrefixed(2, out) return s.readLengthPrefixed(2, out)
} }
// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit // ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
// length-prefixed value into out and advances over it. It returns true on // length-prefixed value into out and advances over it. It reports whether
// success and false on error. // the read was successful.
func (s *String) ReadUint24LengthPrefixed(out *String) bool { func (s *String) ReadUint24LengthPrefixed(out *String) bool {
return s.readLengthPrefixed(3, out) return s.readLengthPrefixed(3, out)
} }
// ReadBytes reads n bytes into out and advances over them. It returns true on // ReadBytes reads n bytes into out and advances over them. It reports
// success and false and error. // whether the read was successful.
func (s *String) ReadBytes(out *[]byte, n int) bool { func (s *String) ReadBytes(out *[]byte, n int) bool {
v := s.read(n) v := s.read(n)
if v == nil { if v == nil {
@ -150,8 +149,8 @@ func (s *String) ReadBytes(out *[]byte, n int) bool {
return true return true
} }
// CopyBytes copies len(out) bytes into out and advances over them. It returns // CopyBytes copies len(out) bytes into out and advances over them. It reports
// true on success and false on error. // whether the copy operation was successful
func (s *String) CopyBytes(out []byte) bool { func (s *String) CopyBytes(out []byte) bool {
n := len(out) n := len(out)
v := s.read(n) v := s.read(n)

View File

@ -488,10 +488,6 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
return nil, err return nil, err
} }
if len(basicResp.Certificates) > 1 {
return nil, ParseError("OCSP response contains bad number of certificates")
}
if n := len(basicResp.TBSResponseData.Responses); n == 0 || cert == nil && n > 1 { if n := len(basicResp.TBSResponseData.Responses); n == 0 || cert == nil && n > 1 {
return nil, ParseError("OCSP response contains bad number of responses") return nil, ParseError("OCSP response contains bad number of responses")
} }
@ -544,6 +540,13 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
} }
if len(basicResp.Certificates) > 0 { if len(basicResp.Certificates) > 0 {
// Responders should only send a single certificate (if they
// send any) that connects the responder's certificate to the
// original issuer. We accept responses with multiple
// certificates due to a number responders sending them[1], but
// ignore all but the first.
//
// [1] https://github.com/golang/go/issues/21527
ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes) ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
if err != nil { if err != nil {
return nil, err return nil, err

15
vendor/gopkg.in/check.v1/check.go generated vendored
View File

@ -239,7 +239,7 @@ func (c *C) logValue(label string, value interface{}) {
} }
} }
func (c *C) logMultiLine(s string) { func formatMultiLine(s string, quote bool) []byte {
b := make([]byte, 0, len(s)*2) b := make([]byte, 0, len(s)*2)
i := 0 i := 0
n := len(s) n := len(s)
@ -249,14 +249,23 @@ func (c *C) logMultiLine(s string) {
j++ j++
} }
b = append(b, "... "...) b = append(b, "... "...)
if quote {
b = strconv.AppendQuote(b, s[i:j]) b = strconv.AppendQuote(b, s[i:j])
if j < n { } else {
b = append(b, s[i:j]...)
b = bytes.TrimSpace(b)
}
if quote && j < n {
b = append(b, " +"...) b = append(b, " +"...)
} }
b = append(b, '\n') b = append(b, '\n')
i = j i = j
} }
c.writeLog(b) return b
}
func (c *C) logMultiLine(s string) {
c.writeLog(formatMultiLine(s, true))
} }
func isMultiLine(s string) bool { func isMultiLine(s string) bool {

View File

@ -187,8 +187,8 @@ func checkState(c *check.C, result interface{}, expected *expectedState) {
log := c.GetTestLog() log := c.GetTestLog()
matched, matchError := regexp.MatchString("^"+expected.log+"$", log) matched, matchError := regexp.MatchString("^"+expected.log+"$", log)
if matchError != nil { if matchError != nil {
c.Errorf("Error in matching expression used in testing %s", c.Errorf("Error in matching expression used in testing %s: %v",
expected.name) expected.name, matchError)
} else if !matched { } else if !matched {
c.Errorf("%s logged:\n----------\n%s----------\n\nExpected:\n----------\n%s\n----------", c.Errorf("%s logged:\n----------\n%s----------\n\nExpected:\n----------\n%s\n----------",
expected.name, log, expected.log) expected.name, log, expected.log)

70
vendor/gopkg.in/check.v1/checkers.go generated vendored
View File

@ -4,6 +4,9 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"regexp" "regexp"
"strings"
"github.com/kr/pretty"
) )
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -90,6 +93,10 @@ func (checker *notChecker) Info() *CheckerInfo {
func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) { func (checker *notChecker) Check(params []interface{}, names []string) (result bool, error string) {
result, error = checker.sub.Check(params, names) result, error = checker.sub.Check(params, names)
result = !result result = !result
if result {
// clear error message if the new result is true
error = ""
}
return return
} }
@ -153,6 +160,56 @@ func (checker *notNilChecker) Check(params []interface{}, names []string) (resul
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Equals checker. // Equals checker.
func diffworthy(a interface{}) bool {
t := reflect.TypeOf(a)
switch t.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct, reflect.String, reflect.Ptr:
return true
}
return false
}
// formatUnequal will dump the actual and expected values into a textual
// representation and return an error message containing a diff.
func formatUnequal(obtained interface{}, expected interface{}) string {
// We do not do diffs for basic types because go-check already
// shows them very cleanly.
if !diffworthy(obtained) || !diffworthy(expected) {
return ""
}
// Handle strings, short strings are ignored (go-check formats
// them very nicely already). We do multi-line strings by
// generating two string slices and using kr.Diff to compare
// those (kr.Diff does not do string diffs by itself).
aStr, aOK := obtained.(string)
bStr, bOK := expected.(string)
if aOK && bOK {
l1 := strings.Split(aStr, "\n")
l2 := strings.Split(bStr, "\n")
// the "2" here is a bit arbitrary
if len(l1) > 2 && len(l2) > 2 {
diff := pretty.Diff(l1, l2)
return fmt.Sprintf(`String difference:
%s`, formatMultiLine(strings.Join(diff, "\n"), false))
}
// string too short
return ""
}
// generic diff
diff := pretty.Diff(obtained, expected)
if len(diff) == 0 {
// No diff, this happens when e.g. just struct
// pointers are different but the structs have
// identical values.
return ""
}
return fmt.Sprintf(`Difference:
%s`, formatMultiLine(strings.Join(diff, "\n"), false))
}
type equalsChecker struct { type equalsChecker struct {
*CheckerInfo *CheckerInfo
} }
@ -175,7 +232,12 @@ func (checker *equalsChecker) Check(params []interface{}, names []string) (resul
error = fmt.Sprint(v) error = fmt.Sprint(v)
} }
}() }()
return params[0] == params[1], ""
result = params[0] == params[1]
if !result {
error = formatUnequal(params[0], params[1])
}
return
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -200,7 +262,11 @@ var DeepEquals Checker = &deepEqualsChecker{
} }
func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) { func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
return reflect.DeepEqual(params[0], params[1]), "" result = reflect.DeepEqual(params[0], params[1])
if !result {
error = formatUnequal(params[0], params[1])
}
return
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------

View File

@ -2,9 +2,10 @@ package check_test
import ( import (
"errors" "errors"
"gopkg.in/check.v1"
"reflect" "reflect"
"runtime" "runtime"
"gopkg.in/check.v1"
) )
type CheckersS struct{} type CheckersS struct{}
@ -77,6 +78,7 @@ func (s *CheckersS) TestNot(c *check.C) {
testCheck(c, check.Not(check.IsNil), false, "", nil) testCheck(c, check.Not(check.IsNil), false, "", nil)
testCheck(c, check.Not(check.IsNil), true, "", "a") testCheck(c, check.Not(check.IsNil), true, "", "a")
testCheck(c, check.Not(check.Equals), true, "", 42, 43)
} }
type simpleStruct struct { type simpleStruct struct {
@ -101,11 +103,16 @@ func (s *CheckersS) TestEquals(c *check.C) {
// Struct values // Struct values
testCheck(c, check.Equals, true, "", simpleStruct{1}, simpleStruct{1}) testCheck(c, check.Equals, true, "", simpleStruct{1}, simpleStruct{1})
testCheck(c, check.Equals, false, "", simpleStruct{1}, simpleStruct{2}) testCheck(c, check.Equals, false, `Difference:
... i: 1 != 2
`, simpleStruct{1}, simpleStruct{2})
// Struct pointers // Struct pointers, no difference in values, just pointer
testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{1}) testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{1})
testCheck(c, check.Equals, false, "", &simpleStruct{1}, &simpleStruct{2}) // Struct pointers, different pointers and different values
testCheck(c, check.Equals, false, `Difference:
... i: 1 != 2
`, &simpleStruct{1}, &simpleStruct{2})
} }
func (s *CheckersS) TestDeepEquals(c *check.C) { func (s *CheckersS) TestDeepEquals(c *check.C) {
@ -123,15 +130,23 @@ func (s *CheckersS) TestDeepEquals(c *check.C) {
// Slices // Slices
testCheck(c, check.DeepEquals, true, "", []byte{1, 2}, []byte{1, 2}) testCheck(c, check.DeepEquals, true, "", []byte{1, 2}, []byte{1, 2})
testCheck(c, check.DeepEquals, false, "", []byte{1, 2}, []byte{1, 3}) testCheck(c, check.DeepEquals, false, `Difference:
... [1]: 2 != 3
`, []byte{1, 2}, []byte{1, 3})
// Struct values // Struct values
testCheck(c, check.DeepEquals, true, "", simpleStruct{1}, simpleStruct{1}) testCheck(c, check.DeepEquals, true, "", simpleStruct{1}, simpleStruct{1})
testCheck(c, check.DeepEquals, false, "", simpleStruct{1}, simpleStruct{2}) testCheck(c, check.DeepEquals, false, `Difference:
... i: 1 != 2
`, simpleStruct{1}, simpleStruct{2})
// Struct pointers // Struct pointers
testCheck(c, check.DeepEquals, true, "", &simpleStruct{1}, &simpleStruct{1}) testCheck(c, check.DeepEquals, true, "", &simpleStruct{1}, &simpleStruct{1})
testCheck(c, check.DeepEquals, false, "", &simpleStruct{1}, &simpleStruct{2}) s1 := &simpleStruct{1}
s2 := &simpleStruct{2}
testCheck(c, check.DeepEquals, false, `Difference:
... i: 1 != 2
`, s1, s2)
} }
func (s *CheckersS) TestHasLen(c *check.C) { func (s *CheckersS) TestHasLen(c *check.C) {

94
vendor/gopkg.in/check.v1/integration_test.go generated vendored Normal file
View File

@ -0,0 +1,94 @@
// Integration tests
package check_test
import (
. "gopkg.in/check.v1"
)
// -----------------------------------------------------------------------
// Integration test suite.
type integrationS struct{}
var _ = Suite(&integrationS{})
type integrationTestHelper struct{}
func (s *integrationTestHelper) TestMultiLineStringEqualFails(c *C) {
c.Check("foo\nbar\nbaz\nboom\n", Equals, "foo\nbaar\nbaz\nboom\n")
}
func (s *integrationTestHelper) TestStringEqualFails(c *C) {
c.Check("foo", Equals, "bar")
}
func (s *integrationTestHelper) TestIntEqualFails(c *C) {
c.Check(42, Equals, 43)
}
type complexStruct struct {
r, i int
}
func (s *integrationTestHelper) TestStructEqualFails(c *C) {
c.Check(complexStruct{1, 2}, Equals, complexStruct{3, 4})
}
func (s *integrationS) TestOutput(c *C) {
helper := integrationTestHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
c.Assert(output.value, Equals, `
----------------------------------------------------------------------
FAIL: integration_test.go:26: integrationTestHelper.TestIntEqualFails
integration_test.go:27:
c.Check(42, Equals, 43)
... obtained int = 42
... expected int = 43
----------------------------------------------------------------------
FAIL: integration_test.go:18: integrationTestHelper.TestMultiLineStringEqualFails
integration_test.go:19:
c.Check("foo\nbar\nbaz\nboom\n", Equals, "foo\nbaar\nbaz\nboom\n")
... obtained string = "" +
... "foo\n" +
... "bar\n" +
... "baz\n" +
... "boom\n"
... expected string = "" +
... "foo\n" +
... "baar\n" +
... "baz\n" +
... "boom\n"
... String difference:
... [1]: "bar" != "baar"
----------------------------------------------------------------------
FAIL: integration_test.go:22: integrationTestHelper.TestStringEqualFails
integration_test.go:23:
c.Check("foo", Equals, "bar")
... obtained string = "foo"
... expected string = "bar"
----------------------------------------------------------------------
FAIL: integration_test.go:34: integrationTestHelper.TestStructEqualFails
integration_test.go:35:
c.Check(complexStruct{1, 2}, Equals, complexStruct{3, 4})
... obtained check_test.complexStruct = check_test.complexStruct{r:1, i:2}
... expected check_test.complexStruct = check_test.complexStruct{r:3, i:4}
... Difference:
... r: 1 != 3
... i: 2 != 4
`)
}

View File

@ -45,8 +45,11 @@ func (s *DirStore) GetOrCreate(tag, item string, create func(io.Writer) error) (
return return
} }
partFile := fullPath + ".part"
os.Remove(partFile)
var out *os.File var out *os.File
out, err = os.OpenFile(fullPath+".part", os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_EXCL, 0600) out, err = os.OpenFile(partFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY|os.O_EXCL, 0600)
if err != nil { if err != nil {
return return
} }

View File

@ -17,12 +17,13 @@ type Config struct {
Clusters []*Cluster Clusters []*Cluster
Configs []*Template Configs []*Template
StaticPods []*Template `yaml:"static_pods"` StaticPods []*Template `yaml:"static_pods"`
Addons map[string][]*Template
SSLConfig string `yaml:"ssl_config"` SSLConfig string `yaml:"ssl_config"`
CertRequests []*CertRequest `yaml:"cert_requests"` CertRequests []*CertRequest `yaml:"cert_requests"`
} }
func FromBytes(data []byte) (*Config, error) { func FromBytes(data []byte) (*Config, error) {
config := &Config{} config := &Config{Addons: make(map[string][]*Template)}
if err := yaml.Unmarshal(data, config); err != nil { if err := yaml.Unmarshal(data, config); err != nil {
return nil, err return nil, err
} }
@ -192,6 +193,7 @@ type Vars map[string]interface{}
type Cluster struct { type Cluster struct {
Name string Name string
Domain string Domain string
Addons string
Subnets struct { Subnets struct {
Services string Services string
Pods string Pods string

View File

@ -11,7 +11,7 @@ import (
) )
func FromDir(dirPath string) (*Config, error) { func FromDir(dirPath string) (*Config, error) {
config := &Config{} config := &Config{Addons: make(map[string][]*Template)}
store := dirStore{dirPath} store := dirStore{dirPath}
load := func(dir, name string, out interface{}) error { load := func(dir, name string, out interface{}) error {
@ -95,6 +95,23 @@ func FromDir(dirPath string) (*Config, error) {
return nil, err return nil, err
} }
{
addonSets, err := store.listDir("addons")
if err != nil {
return nil, err
}
for _, addonSet := range addonSets {
templates := make([]*Template, 0)
if err = loadTemplates(path.Join("addons", addonSet), &templates); err != nil {
return nil, err
}
config.Addons[addonSet] = templates
}
}
// load SSL configuration
if ba, err := ioutil.ReadFile(filepath.Join(dirPath, "ssl-config.json")); err == nil { if ba, err := ioutil.ReadFile(filepath.Join(dirPath, "ssl-config.json")); err == nil {
config.SSLConfig = string(ba) config.SSLConfig = string(ba)
@ -121,6 +138,32 @@ type dirStore struct {
path string path string
} }
// listDir
func (b *dirStore) listDir(prefix string) (subDirs []string, err error) {
entries, err := ioutil.ReadDir(filepath.Join(b.path, prefix))
if err != nil {
return
}
subDirs = make([]string, 0, len(entries))
for _, entry := range entries {
if !entry.IsDir() {
continue
}
name := entry.Name()
if len(name) == 0 || name[0] == '.' {
continue
}
subDirs = append(subDirs, name)
}
return
}
// Names is part of the kvStore interface // Names is part of the kvStore interface
func (b *dirStore) List(prefix string) ([]string, error) { func (b *dirStore) List(prefix string) ([]string, error) {
files, err := filepath.Glob(filepath.Join(b.path, filepath.Join(path.Split(prefix)), "*.yaml")) files, err := filepath.Glob(filepath.Join(b.path, filepath.Join(path.Split(prefix)), "*.yaml"))

View File

@ -2,12 +2,54 @@ package config
import ( import (
"fmt" "fmt"
"io/ioutil" "io"
"os" "os"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
// Load a config from a file.
func Load(file string) (config *Config, err error) {
f, err := os.Open(file)
if err != nil {
return
}
defer f.Close()
config, err = Read(f)
if err != nil {
return nil, fmt.Errorf("failed to parse %s: %v", file, err)
}
return
}
// Read a config from a reader.
func Read(reader io.Reader) (config *Config, err error) {
config = &Config{}
err = yaml.NewDecoder(reader).Decode(config)
if err != nil {
return nil, err
}
return
}
// Parse the config in data.
func Parse(data []byte) (config *Config, err error) {
config = &Config{}
err = yaml.Unmarshal(data, config)
if err != nil {
return nil, err
}
return
}
// Config represent this system's configuration // Config represent this system's configuration
type Config struct { type Config struct {
Vars []VarDefault Vars []VarDefault
@ -83,19 +125,3 @@ type NetworkDef struct {
Optional bool Optional bool
Script string Script string
} }
func Load(file string) (config *Config, err error) {
config = &Config{}
configData, err := ioutil.ReadFile(file)
if err != nil {
return nil, fmt.Errorf("failed to read %s: %v", file, err)
}
err = yaml.Unmarshal(configData, config)
if err != nil {
return nil, fmt.Errorf("failed to parse %s: %v", file, err)
}
return
}

17
vendor/vgo.list vendored
View File

@ -1,6 +1,6 @@
# github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e # github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e
github.com/cavaliercoder/go-cpio github.com/cavaliercoder/go-cpio
# github.com/cloudflare/cfssl v0.0.0-20180530085446-275fb308ac70 # github.com/cloudflare/cfssl v0.0.0-20180705210102-ff56ab5eb62a
github.com/cloudflare/cfssl/auth github.com/cloudflare/cfssl/auth
github.com/cloudflare/cfssl/certdb github.com/cloudflare/cfssl/certdb
github.com/cloudflare/cfssl/config github.com/cloudflare/cfssl/config
@ -24,33 +24,38 @@ github.com/golang/protobuf/ptypes
github.com/golang/protobuf/ptypes/any github.com/golang/protobuf/ptypes/any
github.com/golang/protobuf/ptypes/duration github.com/golang/protobuf/ptypes/duration
github.com/golang/protobuf/ptypes/timestamp github.com/golang/protobuf/ptypes/timestamp
# github.com/google/certificate-transparency-go v1.0.19 # github.com/google/certificate-transparency-go v1.0.20
github.com/google/certificate-transparency-go github.com/google/certificate-transparency-go
github.com/google/certificate-transparency-go/asn1 github.com/google/certificate-transparency-go/asn1
github.com/google/certificate-transparency-go/client github.com/google/certificate-transparency-go/client
github.com/google/certificate-transparency-go/client/configpb github.com/google/certificate-transparency-go/client/configpb
github.com/google/certificate-transparency-go/gossip/minimal/x509ext
github.com/google/certificate-transparency-go/jsonclient github.com/google/certificate-transparency-go/jsonclient
github.com/google/certificate-transparency-go/testdata github.com/google/certificate-transparency-go/testdata
github.com/google/certificate-transparency-go/tls github.com/google/certificate-transparency-go/tls
github.com/google/certificate-transparency-go/x509 github.com/google/certificate-transparency-go/x509
github.com/google/certificate-transparency-go/x509/pkix github.com/google/certificate-transparency-go/x509/pkix
github.com/google/certificate-transparency-go/x509util github.com/google/certificate-transparency-go/x509util
# golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4 # github.com/kr/pretty v0.1.0
github.com/kr/pretty
# github.com/kr/text v0.1.0
github.com/kr/text
# golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8
golang.org/x/crypto/cryptobyte golang.org/x/crypto/cryptobyte
golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/cryptobyte/asn1
golang.org/x/crypto/ocsp golang.org/x/crypto/ocsp
golang.org/x/crypto/pkcs12 golang.org/x/crypto/pkcs12
golang.org/x/crypto/pkcs12/internal/rc2 golang.org/x/crypto/pkcs12/internal/rc2
# golang.org/x/net v0.0.0-20180208041118-f5dfe339be1d # golang.org/x/net v0.0.0-20180706051357-32a936f46389
golang.org/x/net/context golang.org/x/net/context
golang.org/x/net/context/ctxhttp golang.org/x/net/context/ctxhttp
# golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f # golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
golang.org/x/sync/errgroup golang.org/x/sync/errgroup
# gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 # gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
gopkg.in/check.v1 gopkg.in/check.v1
# gopkg.in/yaml.v2 v2.2.1 # gopkg.in/yaml.v2 v2.2.1
gopkg.in/yaml.v2 gopkg.in/yaml.v2
# novit.nc/direktil/pkg v0.0.0-20180619202319-3b512e61055e # novit.nc/direktil/pkg v0.0.0-20180707011528-e82b59c0324d
novit.nc/direktil/pkg/cas novit.nc/direktil/pkg/cas
novit.nc/direktil/pkg/clustersconfig novit.nc/direktil/pkg/clustersconfig
novit.nc/direktil/pkg/config novit.nc/direktil/pkg/config