vendor
This commit is contained in:
17
vendor/github.com/google/certificate-transparency-go/client/configpb/gen.go
generated
vendored
Normal file
17
vendor/github.com/google/certificate-transparency-go/client/configpb/gen.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2017 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 configpb
|
||||
|
||||
//go:generate protoc -I=. -I=$GOPATH/src --go_out=:. multilog.proto
|
124
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.pb.go
generated
vendored
Normal file
124
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.pb.go
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: multilog.proto
|
||||
|
||||
/*
|
||||
Package configpb is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
multilog.proto
|
||||
|
||||
It has these top-level messages:
|
||||
TemporalLogConfig
|
||||
LogShardConfig
|
||||
*/
|
||||
package configpb
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// TemporalLogConfig is a set of LogShardConfig messages, whose
|
||||
// time limits should be contiguous.
|
||||
type TemporalLogConfig struct {
|
||||
Shard []*LogShardConfig `protobuf:"bytes,1,rep,name=shard" json:"shard,omitempty"`
|
||||
}
|
||||
|
||||
func (m *TemporalLogConfig) Reset() { *m = TemporalLogConfig{} }
|
||||
func (m *TemporalLogConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*TemporalLogConfig) ProtoMessage() {}
|
||||
func (*TemporalLogConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *TemporalLogConfig) GetShard() []*LogShardConfig {
|
||||
if m != nil {
|
||||
return m.Shard
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LogShardConfig describes the acceptable date range for a single shard of a temporal
|
||||
// log.
|
||||
type LogShardConfig struct {
|
||||
Uri string `protobuf:"bytes,1,opt,name=uri" json:"uri,omitempty"`
|
||||
// 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"`
|
||||
// not_after_start defines the start of the range of acceptable NotAfter
|
||||
// values, inclusive.
|
||||
// Leaving this unset implies no lower bound to the range.
|
||||
NotAfterStart *google_protobuf.Timestamp `protobuf:"bytes,3,opt,name=not_after_start,json=notAfterStart" json:"not_after_start,omitempty"`
|
||||
// not_after_limit defines the end of the range of acceptable NotAfter values,
|
||||
// exclusive.
|
||||
// Leaving this unset implies no upper bound to the range.
|
||||
NotAfterLimit *google_protobuf.Timestamp `protobuf:"bytes,4,opt,name=not_after_limit,json=notAfterLimit" json:"not_after_limit,omitempty"`
|
||||
}
|
||||
|
||||
func (m *LogShardConfig) Reset() { *m = LogShardConfig{} }
|
||||
func (m *LogShardConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*LogShardConfig) ProtoMessage() {}
|
||||
func (*LogShardConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
func (m *LogShardConfig) GetUri() string {
|
||||
if m != nil {
|
||||
return m.Uri
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *LogShardConfig) GetPublicKeyDer() []byte {
|
||||
if m != nil {
|
||||
return m.PublicKeyDer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LogShardConfig) GetNotAfterStart() *google_protobuf.Timestamp {
|
||||
if m != nil {
|
||||
return m.NotAfterStart
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *LogShardConfig) GetNotAfterLimit() *google_protobuf.Timestamp {
|
||||
if m != nil {
|
||||
return m.NotAfterLimit
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*TemporalLogConfig)(nil), "configpb.TemporalLogConfig")
|
||||
proto.RegisterType((*LogShardConfig)(nil), "configpb.LogShardConfig")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("multilog.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 241 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x8f, 0xb1, 0x4e, 0xc3, 0x30,
|
||||
0x14, 0x45, 0x65, 0x02, 0x08, 0xdc, 0x12, 0xc0, 0x93, 0xd5, 0x85, 0xa8, 0x62, 0xc8, 0xe4, 0x4a,
|
||||
0xe5, 0x0b, 0xa0, 0x6c, 0x64, 0x4a, 0xbb, 0x47, 0x4e, 0xeb, 0x18, 0x0b, 0x3b, 0xcf, 0x72, 0x5e,
|
||||
0x86, 0xfe, 0x25, 0x9f, 0x84, 0x1c, 0x2b, 0x43, 0x37, 0xb6, 0xa7, 0x77, 0xcf, 0xb9, 0xd2, 0xa5,
|
||||
0xb9, 0x1b, 0x2d, 0x1a, 0x0b, 0x5a, 0xf8, 0x00, 0x08, 0xec, 0xee, 0x08, 0x7d, 0x67, 0xb4, 0x6f,
|
||||
0x57, 0x2f, 0x1a, 0x40, 0x5b, 0xb5, 0x99, 0xfe, 0xed, 0xd8, 0x6d, 0xd0, 0x38, 0x35, 0xa0, 0x74,
|
||||
0x3e, 0xa1, 0xeb, 0x1d, 0x7d, 0x3e, 0x28, 0xe7, 0x21, 0x48, 0x5b, 0x81, 0xde, 0x4d, 0x1e, 0x13,
|
||||
0xf4, 0x66, 0xf8, 0x96, 0xe1, 0xc4, 0x49, 0x91, 0x95, 0x8b, 0x2d, 0x17, 0x73, 0x9f, 0xa8, 0x40,
|
||||
0xef, 0x63, 0x92, 0xc0, 0x3a, 0x61, 0xeb, 0x5f, 0x42, 0xf3, 0xcb, 0x84, 0x3d, 0xd1, 0x6c, 0x0c,
|
||||
0x86, 0x93, 0x82, 0x94, 0xf7, 0x75, 0x3c, 0xd9, 0x2b, 0xcd, 0xfd, 0xd8, 0x5a, 0x73, 0x6c, 0x7e,
|
||||
0xd4, 0xb9, 0x39, 0xa9, 0xc0, 0xaf, 0x0a, 0x52, 0x2e, 0xeb, 0x65, 0xfa, 0x7e, 0xa9, 0xf3, 0xa7,
|
||||
0x0a, 0xec, 0x83, 0x3e, 0xf6, 0x80, 0x8d, 0xec, 0x50, 0x85, 0x66, 0x40, 0x19, 0x90, 0x67, 0x05,
|
||||
0x29, 0x17, 0xdb, 0x95, 0x48, 0x53, 0xc4, 0x3c, 0x45, 0x1c, 0xe6, 0x29, 0xf5, 0x43, 0x0f, 0xf8,
|
||||
0x1e, 0x8d, 0x7d, 0x14, 0x2e, 0x3b, 0xac, 0x71, 0x06, 0xf9, 0xf5, 0xff, 0x3b, 0xaa, 0x28, 0xb4,
|
||||
0xb7, 0x13, 0xf2, 0xf6, 0x17, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xd9, 0x50, 0x5b, 0x5b, 0x01, 0x00,
|
||||
0x00,
|
||||
}
|
43
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.proto
generated
vendored
Normal file
43
vendor/github.com/google/certificate-transparency-go/client/configpb/multilog.proto
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package configpb;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
// TemporalLogConfig is a set of LogShardConfig messages, whose
|
||||
// time limits should be contiguous.
|
||||
message TemporalLogConfig {
|
||||
repeated LogShardConfig shard = 1;
|
||||
}
|
||||
|
||||
// LogShardConfig describes the acceptable date range for a single shard of a temporal
|
||||
// log.
|
||||
message LogShardConfig {
|
||||
string uri = 1;
|
||||
|
||||
// The log's public key in DER-encoded PKIX form.
|
||||
bytes public_key_der = 2;
|
||||
|
||||
// not_after_start defines the start of the range of acceptable NotAfter
|
||||
// values, inclusive.
|
||||
// Leaving this unset implies no lower bound to the range.
|
||||
google.protobuf.Timestamp not_after_start = 3;
|
||||
// not_after_limit defines the end of the range of acceptable NotAfter values,
|
||||
// exclusive.
|
||||
// Leaving this unset implies no upper bound to the range.
|
||||
google.protobuf.Timestamp not_after_limit = 4;
|
||||
}
|
75
vendor/github.com/google/certificate-transparency-go/client/getentries.go
generated
vendored
Normal file
75
vendor/github.com/google/certificate-transparency-go/client/getentries.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2016 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
ct "github.com/google/certificate-transparency-go"
|
||||
"github.com/google/certificate-transparency-go/x509"
|
||||
)
|
||||
|
||||
// GetRawEntries exposes the /ct/v1/get-entries result with only the JSON parsing done.
|
||||
func (c *LogClient) GetRawEntries(ctx context.Context, start, end int64) (*ct.GetEntriesResponse, error) {
|
||||
if end < 0 {
|
||||
return nil, errors.New("end should be >= 0")
|
||||
}
|
||||
if end < start {
|
||||
return nil, errors.New("start should be <= end")
|
||||
}
|
||||
|
||||
params := map[string]string{
|
||||
"start": strconv.FormatInt(start, 10),
|
||||
"end": strconv.FormatInt(end, 10),
|
||||
}
|
||||
if ctx == nil {
|
||||
ctx = context.TODO()
|
||||
}
|
||||
|
||||
var resp ct.GetEntriesResponse
|
||||
httpRsp, body, err := c.GetAndParse(ctx, ct.GetEntriesPath, params, &resp)
|
||||
if err != nil {
|
||||
if httpRsp != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// GetEntries attempts to retrieve the entries in the sequence [start, end] from the CT log server
|
||||
// (RFC6962 s4.6) as parsed [pre-]certificates for convenience, held in a slice of ct.LogEntry structures.
|
||||
// However, this does mean that any certificate parsing failures will cause a failure of the whole
|
||||
// retrieval operation; for more robust retrieval of parsed certificates, use GetRawEntries() and invoke
|
||||
// ct.LogEntryFromLeaf() on each individual entry.
|
||||
func (c *LogClient) GetEntries(ctx context.Context, start, end int64) ([]ct.LogEntry, error) {
|
||||
resp, err := c.GetRawEntries(ctx, start, end)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries := make([]ct.LogEntry, len(resp.Entries))
|
||||
for i, entry := range resp.Entries {
|
||||
index := start + int64(i)
|
||||
logEntry, err := ct.LogEntryFromLeaf(index, &entry)
|
||||
if _, ok := err.(x509.NonFatalErrors); !ok && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
entries[i] = *logEntry
|
||||
}
|
||||
return entries, nil
|
||||
}
|
283
vendor/github.com/google/certificate-transparency-go/client/logclient.go
generated
vendored
Normal file
283
vendor/github.com/google/certificate-transparency-go/client/logclient.go
generated
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
// Copyright 2014 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 client is a CT log client implementation and contains types and code
|
||||
// for interacting with RFC6962-compliant CT Log instances.
|
||||
// See http://tools.ietf.org/html/rfc6962 for details
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
ct "github.com/google/certificate-transparency-go"
|
||||
"github.com/google/certificate-transparency-go/jsonclient"
|
||||
"github.com/google/certificate-transparency-go/tls"
|
||||
)
|
||||
|
||||
// LogClient represents a client for a given CT Log instance
|
||||
type LogClient struct {
|
||||
jsonclient.JSONClient
|
||||
}
|
||||
|
||||
// New constructs a new LogClient instance.
|
||||
// |uri| is the base URI of the CT log instance to interact with, e.g.
|
||||
// http://ct.googleapis.com/pilot
|
||||
// |hc| is the underlying client to be used for HTTP requests to the CT log.
|
||||
// |opts| can be used to provide a customer logger interface and a public key
|
||||
// for signature verification.
|
||||
func New(uri string, hc *http.Client, opts jsonclient.Options) (*LogClient, error) {
|
||||
logClient, err := jsonclient.New(uri, hc, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LogClient{*logClient}, err
|
||||
}
|
||||
|
||||
// RspError represents an error that occurred when processing a response from a server,
|
||||
// and also includes key details from the http.Response that triggered the error.
|
||||
type RspError struct {
|
||||
Err error
|
||||
StatusCode int
|
||||
Body []byte
|
||||
}
|
||||
|
||||
// Error formats the RspError instance, focusing on the error.
|
||||
func (e RspError) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
// Attempts to add |chain| to the log, using the api end-point specified by
|
||||
// |path|. If provided context expires before submission is complete an
|
||||
// error will be returned.
|
||||
func (c *LogClient) addChainWithRetry(ctx context.Context, ctype ct.LogEntryType, path string, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||
var resp ct.AddChainResponse
|
||||
var req ct.AddChainRequest
|
||||
for _, link := range chain {
|
||||
req.Chain = append(req.Chain, link.Data)
|
||||
}
|
||||
|
||||
httpRsp, body, err := c.PostAndParseWithRetry(ctx, path, &req, &resp)
|
||||
if err != nil {
|
||||
if httpRsp != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ds ct.DigitallySigned
|
||||
if rest, err := tls.Unmarshal(resp.Signature, &ds); err != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
} else if len(rest) > 0 {
|
||||
return nil, RspError{
|
||||
Err: fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)),
|
||||
StatusCode: httpRsp.StatusCode,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
exts, err := base64.StdEncoding.DecodeString(resp.Extensions)
|
||||
if err != nil {
|
||||
return nil, RspError{
|
||||
Err: fmt.Errorf("invalid base64 data in Extensions (%q): %v", resp.Extensions, err),
|
||||
StatusCode: httpRsp.StatusCode,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
var logID ct.LogID
|
||||
copy(logID.KeyID[:], resp.ID)
|
||||
sct := &ct.SignedCertificateTimestamp{
|
||||
SCTVersion: resp.SCTVersion,
|
||||
LogID: logID,
|
||||
Timestamp: resp.Timestamp,
|
||||
Extensions: ct.CTExtensions(exts),
|
||||
Signature: ds,
|
||||
}
|
||||
if err := c.VerifySCTSignature(*sct, ctype, chain); err != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return sct, nil
|
||||
}
|
||||
|
||||
// AddChain adds the (DER represented) X509 |chain| to the log.
|
||||
func (c *LogClient) AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||
return c.addChainWithRetry(ctx, ct.X509LogEntryType, ct.AddChainPath, chain)
|
||||
}
|
||||
|
||||
// AddPreChain adds the (DER represented) Precertificate |chain| to the log.
|
||||
func (c *LogClient) AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||
return c.addChainWithRetry(ctx, ct.PrecertLogEntryType, ct.AddPreChainPath, chain)
|
||||
}
|
||||
|
||||
// AddJSON submits arbitrary data to to XJSON server.
|
||||
func (c *LogClient) AddJSON(ctx context.Context, data interface{}) (*ct.SignedCertificateTimestamp, error) {
|
||||
req := ct.AddJSONRequest{Data: data}
|
||||
var resp ct.AddChainResponse
|
||||
httpRsp, body, err := c.PostAndParse(ctx, ct.AddJSONPath, &req, &resp)
|
||||
if err != nil {
|
||||
if httpRsp != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var ds ct.DigitallySigned
|
||||
if rest, err := tls.Unmarshal(resp.Signature, &ds); err != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
} else if len(rest) > 0 {
|
||||
return nil, RspError{
|
||||
Err: fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)),
|
||||
StatusCode: httpRsp.StatusCode,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
var logID ct.LogID
|
||||
copy(logID.KeyID[:], resp.ID)
|
||||
return &ct.SignedCertificateTimestamp{
|
||||
SCTVersion: resp.SCTVersion,
|
||||
LogID: logID,
|
||||
Timestamp: resp.Timestamp,
|
||||
Extensions: ct.CTExtensions(resp.Extensions),
|
||||
Signature: ds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetSTH retrieves the current STH from the log.
|
||||
// Returns a populated SignedTreeHead, or a non-nil error (which may be of type
|
||||
// RspError if a raw http.Response is available).
|
||||
func (c *LogClient) GetSTH(ctx context.Context) (*ct.SignedTreeHead, error) {
|
||||
var resp ct.GetSTHResponse
|
||||
httpRsp, body, err := c.GetAndParse(ctx, ct.GetSTHPath, nil, &resp)
|
||||
if err != nil {
|
||||
if httpRsp != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
sth := ct.SignedTreeHead{
|
||||
TreeSize: resp.TreeSize,
|
||||
Timestamp: resp.Timestamp,
|
||||
}
|
||||
|
||||
if len(resp.SHA256RootHash) != sha256.Size {
|
||||
return nil, RspError{
|
||||
Err: fmt.Errorf("sha256_root_hash is invalid length, expected %d got %d", sha256.Size, len(resp.SHA256RootHash)),
|
||||
StatusCode: httpRsp.StatusCode,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
copy(sth.SHA256RootHash[:], resp.SHA256RootHash)
|
||||
|
||||
var ds ct.DigitallySigned
|
||||
if rest, err := tls.Unmarshal(resp.TreeHeadSignature, &ds); err != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
} else if len(rest) > 0 {
|
||||
return nil, RspError{
|
||||
Err: fmt.Errorf("trailing data (%d bytes) after DigitallySigned", len(rest)),
|
||||
StatusCode: httpRsp.StatusCode,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
sth.TreeHeadSignature = ds
|
||||
if err := c.VerifySTHSignature(sth); err != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return &sth, nil
|
||||
}
|
||||
|
||||
// VerifySTHSignature checks the signature in sth, returning any error encountered or nil if verification is
|
||||
// successful.
|
||||
func (c *LogClient) VerifySTHSignature(sth ct.SignedTreeHead) error {
|
||||
if c.Verifier == nil {
|
||||
// Can't verify signatures without a verifier
|
||||
return nil
|
||||
}
|
||||
return c.Verifier.VerifySTHSignature(sth)
|
||||
}
|
||||
|
||||
// VerifySCTSignature checks the signature in sct for the given LogEntryType, with associated certificate chain.
|
||||
func (c *LogClient) VerifySCTSignature(sct ct.SignedCertificateTimestamp, ctype ct.LogEntryType, certData []ct.ASN1Cert) error {
|
||||
if c.Verifier == nil {
|
||||
// Can't verify signatures without a verifier
|
||||
return nil
|
||||
}
|
||||
leaf, err := ct.MerkleTreeLeafFromRawChain(certData, ctype, sct.Timestamp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build MerkleTreeLeaf: %v", err)
|
||||
}
|
||||
entry := ct.LogEntry{Leaf: *leaf}
|
||||
return c.Verifier.VerifySCTSignature(sct, entry)
|
||||
}
|
||||
|
||||
// GetSTHConsistency retrieves the consistency proof between two snapshots.
|
||||
func (c *LogClient) GetSTHConsistency(ctx context.Context, first, second uint64) ([][]byte, error) {
|
||||
base10 := 10
|
||||
params := map[string]string{
|
||||
"first": strconv.FormatUint(first, base10),
|
||||
"second": strconv.FormatUint(second, base10),
|
||||
}
|
||||
var resp ct.GetSTHConsistencyResponse
|
||||
httpRsp, body, err := c.GetAndParse(ctx, ct.GetSTHConsistencyPath, params, &resp)
|
||||
if err != nil {
|
||||
if httpRsp != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return resp.Consistency, nil
|
||||
}
|
||||
|
||||
// GetProofByHash returns an audit path for the hash of an SCT.
|
||||
func (c *LogClient) GetProofByHash(ctx context.Context, hash []byte, treeSize uint64) (*ct.GetProofByHashResponse, error) {
|
||||
b64Hash := base64.StdEncoding.EncodeToString(hash)
|
||||
base10 := 10
|
||||
params := map[string]string{
|
||||
"tree_size": strconv.FormatUint(treeSize, base10),
|
||||
"hash": b64Hash,
|
||||
}
|
||||
var resp ct.GetProofByHashResponse
|
||||
httpRsp, body, err := c.GetAndParse(ctx, ct.GetProofByHashPath, params, &resp)
|
||||
if err != nil {
|
||||
if httpRsp != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// GetAcceptedRoots retrieves the set of acceptable root certificates for a log.
|
||||
func (c *LogClient) GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error) {
|
||||
var resp ct.GetRootsResponse
|
||||
httpRsp, body, err := c.GetAndParse(ctx, ct.GetRootsPath, nil, &resp)
|
||||
if err != nil {
|
||||
if httpRsp != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var roots []ct.ASN1Cert
|
||||
for _, cert64 := range resp.Certificates {
|
||||
cert, err := base64.StdEncoding.DecodeString(cert64)
|
||||
if err != nil {
|
||||
return nil, RspError{Err: err, StatusCode: httpRsp.StatusCode, Body: body}
|
||||
}
|
||||
roots = append(roots, ct.ASN1Cert{Data: cert})
|
||||
}
|
||||
return roots, nil
|
||||
}
|
713
vendor/github.com/google/certificate-transparency-go/client/logclient_test.go
generated
vendored
Normal file
713
vendor/github.com/google/certificate-transparency-go/client/logclient_test.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
221
vendor/github.com/google/certificate-transparency-go/client/multilog.go
generated
vendored
Normal file
221
vendor/github.com/google/certificate-transparency-go/client/multilog.go
generated
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
// Copyright 2017 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
ct "github.com/google/certificate-transparency-go"
|
||||
"github.com/google/certificate-transparency-go/client/configpb"
|
||||
"github.com/google/certificate-transparency-go/jsonclient"
|
||||
"github.com/google/certificate-transparency-go/x509"
|
||||
)
|
||||
|
||||
type interval struct {
|
||||
lower *time.Time // nil => no lower bound
|
||||
upper *time.Time // nil => no upper bound
|
||||
}
|
||||
|
||||
// TemporalLogConfigFromFile creates a TemporalLogConfig object from the given
|
||||
// filename, which should contain text-protobuf encoded configuration data.
|
||||
func TemporalLogConfigFromFile(filename string) (*configpb.TemporalLogConfig, error) {
|
||||
if len(filename) == 0 {
|
||||
return nil, errors.New("log config filename empty")
|
||||
}
|
||||
|
||||
cfgText, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read log config: %v", err)
|
||||
}
|
||||
|
||||
var cfg configpb.TemporalLogConfig
|
||||
if err := proto.UnmarshalText(string(cfgText), &cfg); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse log config: %v", err)
|
||||
}
|
||||
|
||||
if len(cfg.Shard) == 0 {
|
||||
return nil, errors.New("empty log config found")
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// AddLogClient is an interface that allows adding certificates and pre-certificates to a log.
|
||||
// Both LogClient and TemporalLogClient implement this interface, which allows users to
|
||||
// commonize code for adding certs to normal/temporal logs.
|
||||
type AddLogClient interface {
|
||||
AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error)
|
||||
AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error)
|
||||
GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error)
|
||||
}
|
||||
|
||||
// TemporalLogClient allows [pre-]certificates to be uploaded to a temporal log.
|
||||
type TemporalLogClient struct {
|
||||
Clients []*LogClient
|
||||
intervals []interval
|
||||
}
|
||||
|
||||
// NewTemporalLogClient builds a new client for interacting with a temporal log.
|
||||
// The provided config should be contiguous and chronological.
|
||||
func NewTemporalLogClient(cfg configpb.TemporalLogConfig, hc *http.Client) (*TemporalLogClient, error) {
|
||||
if len(cfg.Shard) == 0 {
|
||||
return nil, errors.New("empty config")
|
||||
}
|
||||
|
||||
overall, err := shardInterval(cfg.Shard[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cfg.Shard[0] invalid: %v", err)
|
||||
}
|
||||
intervals := make([]interval, 0, len(cfg.Shard))
|
||||
intervals = append(intervals, overall)
|
||||
for i := 1; i < len(cfg.Shard); i++ {
|
||||
interval, err := shardInterval(cfg.Shard[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cfg.Shard[%d] invalid: %v", i, err)
|
||||
}
|
||||
if overall.upper == nil {
|
||||
return nil, fmt.Errorf("cfg.Shard[%d] extends an interval with no upper bound", i)
|
||||
}
|
||||
if interval.lower == nil {
|
||||
return nil, fmt.Errorf("cfg.Shard[%d] has no lower bound but extends an interval", i)
|
||||
}
|
||||
if !interval.lower.Equal(*overall.upper) {
|
||||
return nil, fmt.Errorf("cfg.Shard[%d] starts at %v but previous interval ended at %v", i, interval.lower, overall.upper)
|
||||
}
|
||||
overall.upper = interval.upper
|
||||
intervals = append(intervals, interval)
|
||||
}
|
||||
clients := make([]*LogClient, 0, len(cfg.Shard))
|
||||
for i, shard := range cfg.Shard {
|
||||
opts := jsonclient.Options{}
|
||||
opts.PublicKeyDER = shard.GetPublicKeyDer()
|
||||
c, err := New(shard.Uri, hc, opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create client for cfg.Shard[%d]: %v", i, err)
|
||||
}
|
||||
clients = append(clients, c)
|
||||
}
|
||||
tlc := TemporalLogClient{
|
||||
Clients: clients,
|
||||
intervals: intervals,
|
||||
}
|
||||
return &tlc, nil
|
||||
}
|
||||
|
||||
// GetAcceptedRoots retrieves the set of acceptable root certificates for all
|
||||
// of the shards of a temporal log (i.e. the union).
|
||||
func (tlc *TemporalLogClient) GetAcceptedRoots(ctx context.Context) ([]ct.ASN1Cert, error) {
|
||||
type result struct {
|
||||
roots []ct.ASN1Cert
|
||||
err error
|
||||
}
|
||||
results := make(chan result, len(tlc.Clients))
|
||||
for _, c := range tlc.Clients {
|
||||
go func(c *LogClient) {
|
||||
var r result
|
||||
r.roots, r.err = c.GetAcceptedRoots(ctx)
|
||||
results <- r
|
||||
}(c)
|
||||
}
|
||||
|
||||
var allRoots []ct.ASN1Cert
|
||||
seen := make(map[[sha256.Size]byte]bool)
|
||||
for range tlc.Clients {
|
||||
r := <-results
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
for _, root := range r.roots {
|
||||
h := sha256.Sum256(root.Data)
|
||||
if seen[h] {
|
||||
continue
|
||||
}
|
||||
seen[h] = true
|
||||
allRoots = append(allRoots, root)
|
||||
}
|
||||
}
|
||||
return allRoots, nil
|
||||
}
|
||||
|
||||
// AddChain adds the (DER represented) X509 chain to the appropriate log.
|
||||
func (tlc *TemporalLogClient) AddChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||
return tlc.addChain(ctx, ct.X509LogEntryType, ct.AddChainPath, chain)
|
||||
}
|
||||
|
||||
// AddPreChain adds the (DER represented) Precertificate chain to the appropriate log.
|
||||
func (tlc *TemporalLogClient) AddPreChain(ctx context.Context, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||
return tlc.addChain(ctx, ct.PrecertLogEntryType, ct.AddPreChainPath, chain)
|
||||
}
|
||||
|
||||
func (tlc *TemporalLogClient) addChain(ctx context.Context, ctype ct.LogEntryType, path string, chain []ct.ASN1Cert) (*ct.SignedCertificateTimestamp, error) {
|
||||
// Parse the first entry in the chain
|
||||
if len(chain) == 0 {
|
||||
return nil, errors.New("missing chain")
|
||||
}
|
||||
cert, err := x509.ParseCertificate(chain[0].Data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse initial chain entry: %v", err)
|
||||
}
|
||||
cidx, err := tlc.IndexByDate(cert.NotAfter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find log to process cert: %v", err)
|
||||
}
|
||||
return tlc.Clients[cidx].addChainWithRetry(ctx, ctype, path, chain)
|
||||
}
|
||||
|
||||
// IndexByDate returns the index of the Clients entry that is appropriate for the given
|
||||
// date.
|
||||
func (tlc *TemporalLogClient) IndexByDate(when time.Time) (int, error) {
|
||||
for i, interval := range tlc.intervals {
|
||||
if (interval.lower != nil) && when.Before(*interval.lower) {
|
||||
continue
|
||||
}
|
||||
if (interval.upper != nil) && !when.Before(*interval.upper) {
|
||||
continue
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return -1, fmt.Errorf("no log found encompassing date %v", when)
|
||||
}
|
||||
|
||||
func shardInterval(cfg *configpb.LogShardConfig) (interval, error) {
|
||||
var interval interval
|
||||
if cfg.NotAfterStart != nil {
|
||||
t, err := ptypes.Timestamp(cfg.NotAfterStart)
|
||||
if err != nil {
|
||||
return interval, fmt.Errorf("failed to parse NotAfterStart: %v", err)
|
||||
}
|
||||
interval.lower = &t
|
||||
}
|
||||
if cfg.NotAfterLimit != nil {
|
||||
t, err := ptypes.Timestamp(cfg.NotAfterLimit)
|
||||
if err != nil {
|
||||
return interval, fmt.Errorf("failed to parse NotAfterLimit: %v", err)
|
||||
}
|
||||
interval.upper = &t
|
||||
}
|
||||
|
||||
if interval.lower != nil && interval.upper != nil && !(*interval.lower).Before(*interval.upper) {
|
||||
return interval, errors.New("inverted interval")
|
||||
}
|
||||
return interval, nil
|
||||
}
|
481
vendor/github.com/google/certificate-transparency-go/client/multilog_test.go
generated
vendored
Normal file
481
vendor/github.com/google/certificate-transparency-go/client/multilog_test.go
generated
vendored
Normal file
@ -0,0 +1,481 @@
|
||||
// Copyright 2017 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/pem"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
tspb "github.com/golang/protobuf/ptypes/timestamp"
|
||||
ct "github.com/google/certificate-transparency-go"
|
||||
"github.com/google/certificate-transparency-go/client/configpb"
|
||||
"github.com/google/certificate-transparency-go/testdata"
|
||||
"github.com/google/certificate-transparency-go/x509util"
|
||||
)
|
||||
|
||||
func TestNewTemporalLogClient(t *testing.T) {
|
||||
ts0, _ := ptypes.TimestampProto(time.Date(2010, 9, 19, 11, 00, 00, 00, time.UTC))
|
||||
ts1, _ := ptypes.TimestampProto(time.Date(2011, 9, 19, 11, 00, 00, 00, time.UTC))
|
||||
ts2, _ := ptypes.TimestampProto(time.Date(2012, 9, 19, 11, 00, 00, 00, time.UTC))
|
||||
ts2_5, _ := ptypes.TimestampProto(time.Date(2013, 3, 19, 11, 00, 00, 00, time.UTC))
|
||||
ts3, _ := ptypes.TimestampProto(time.Date(2013, 9, 19, 11, 00, 00, 00, time.UTC))
|
||||
ts4, _ := ptypes.TimestampProto(time.Date(2014, 9, 19, 11, 00, 00, 00, time.UTC))
|
||||
|
||||
tests := []struct {
|
||||
cfg configpb.TemporalLogConfig
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: nil, NotAfterLimit: nil},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: nil, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: nil, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: nil},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: nil},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "threeA", NotAfterStart: ts2_5, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
},
|
||||
},
|
||||
wantErr: "previous interval ended at",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: nil},
|
||||
},
|
||||
},
|
||||
wantErr: "previous interval ended at",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: nil, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts1},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
},
|
||||
},
|
||||
wantErr: "inverted",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: nil},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: nil},
|
||||
},
|
||||
},
|
||||
wantErr: "no upper bound",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: nil, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: nil},
|
||||
},
|
||||
},
|
||||
wantErr: "has no lower bound",
|
||||
},
|
||||
{
|
||||
wantErr: "empty",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{Shard: []*configpb.LogShardConfig{}},
|
||||
wantErr: "empty",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts1, NotAfterLimit: ts1},
|
||||
},
|
||||
},
|
||||
wantErr: "inverted",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts2, NotAfterLimit: ts1},
|
||||
},
|
||||
},
|
||||
wantErr: "inverted",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: &tspb.Timestamp{Seconds: -1, Nanos: -1}, NotAfterLimit: ts2},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to parse",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "one", NotAfterStart: ts1, NotAfterLimit: &tspb.Timestamp{Seconds: -1, Nanos: -1}},
|
||||
},
|
||||
},
|
||||
wantErr: "failed to parse",
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{
|
||||
Uri: "one",
|
||||
NotAfterStart: nil,
|
||||
NotAfterLimit: nil,
|
||||
PublicKeyDer: []byte{0x01, 0x02},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: "invalid public key",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
_, err := NewTemporalLogClient(test.cfg, nil)
|
||||
if err != nil {
|
||||
if test.wantErr == "" {
|
||||
t.Errorf("NewTemporalLogClient(%+v)=nil,%v; want _,nil", test.cfg, err)
|
||||
} else if !strings.Contains(err.Error(), test.wantErr) {
|
||||
t.Errorf("NewTemporalLogClient(%+v)=nil,%v; want _,%q", test.cfg, err, test.wantErr)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if test.wantErr != "" {
|
||||
t.Errorf("NewTemporalLogClient(%+v)=_, nil; want _,%q", test.cfg, test.wantErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndexByDate(t *testing.T) {
|
||||
time0 := time.Date(2010, 9, 19, 11, 00, 00, 00, time.UTC)
|
||||
time1 := time.Date(2011, 9, 19, 11, 00, 00, 00, time.UTC)
|
||||
time1_9 := time.Date(2012, 9, 19, 10, 59, 59, 00, time.UTC)
|
||||
time2 := time.Date(2012, 9, 19, 11, 00, 00, 00, time.UTC)
|
||||
time2_5 := time.Date(2013, 3, 19, 11, 00, 00, 00, time.UTC)
|
||||
time3 := time.Date(2013, 9, 19, 11, 00, 00, 00, time.UTC)
|
||||
time4 := time.Date(2014, 9, 19, 11, 00, 00, 00, time.UTC)
|
||||
|
||||
ts0, _ := ptypes.TimestampProto(time0)
|
||||
ts1, _ := ptypes.TimestampProto(time1)
|
||||
ts2, _ := ptypes.TimestampProto(time2)
|
||||
ts3, _ := ptypes.TimestampProto(time3)
|
||||
ts4, _ := ptypes.TimestampProto(time4)
|
||||
|
||||
allCfg := configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "zero", NotAfterStart: nil, NotAfterLimit: ts0},
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
{Uri: "five", NotAfterStart: ts4, NotAfterLimit: nil},
|
||||
},
|
||||
}
|
||||
uptoCfg := configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "zero", NotAfterStart: nil, NotAfterLimit: ts0},
|
||||
{Uri: "one", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "two", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "three", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "four", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
},
|
||||
}
|
||||
fromCfg :=
|
||||
configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "zero", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "one", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "two", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "three", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
{Uri: "four", NotAfterStart: ts4, NotAfterLimit: nil},
|
||||
},
|
||||
}
|
||||
boundedCfg :=
|
||||
configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: "zero", NotAfterStart: ts0, NotAfterLimit: ts1},
|
||||
{Uri: "one", NotAfterStart: ts1, NotAfterLimit: ts2},
|
||||
{Uri: "two", NotAfterStart: ts2, NotAfterLimit: ts3},
|
||||
{Uri: "three", NotAfterStart: ts3, NotAfterLimit: ts4},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
cfg configpb.TemporalLogConfig
|
||||
when time.Time
|
||||
want int
|
||||
wantErr bool
|
||||
}{
|
||||
{cfg: allCfg, when: time.Date(2000, 9, 19, 11, 00, 00, 00, time.UTC), want: 0},
|
||||
{cfg: allCfg, when: time0, want: 1},
|
||||
{cfg: allCfg, when: time1, want: 2},
|
||||
{cfg: allCfg, when: time1_9, want: 2},
|
||||
{cfg: allCfg, when: time2, want: 3},
|
||||
{cfg: allCfg, when: time2_5, want: 3},
|
||||
{cfg: allCfg, when: time3, want: 4},
|
||||
{cfg: allCfg, when: time4, want: 5},
|
||||
{cfg: allCfg, when: time.Date(2015, 9, 19, 11, 00, 00, 00, time.UTC), want: 5},
|
||||
|
||||
{cfg: uptoCfg, when: time.Date(2000, 9, 19, 11, 00, 00, 00, time.UTC), want: 0},
|
||||
{cfg: uptoCfg, when: time0, want: 1},
|
||||
{cfg: uptoCfg, when: time1, want: 2},
|
||||
{cfg: uptoCfg, when: time2, want: 3},
|
||||
{cfg: uptoCfg, when: time2_5, want: 3},
|
||||
{cfg: uptoCfg, when: time3, want: 4},
|
||||
{cfg: uptoCfg, when: time4, wantErr: true},
|
||||
{cfg: uptoCfg, when: time.Date(2015, 9, 19, 11, 00, 00, 00, time.UTC), wantErr: true},
|
||||
|
||||
{cfg: fromCfg, when: time.Date(2000, 9, 19, 11, 00, 00, 00, time.UTC), wantErr: true},
|
||||
{cfg: fromCfg, when: time0, want: 0},
|
||||
{cfg: fromCfg, when: time1, want: 1},
|
||||
{cfg: fromCfg, when: time2, want: 2},
|
||||
{cfg: fromCfg, when: time2_5, want: 2},
|
||||
{cfg: fromCfg, when: time3, want: 3},
|
||||
{cfg: fromCfg, when: time4, want: 4},
|
||||
{cfg: fromCfg, when: time.Date(2015, 9, 19, 11, 00, 00, 00, time.UTC), want: 4},
|
||||
|
||||
{cfg: boundedCfg, when: time.Date(2000, 9, 19, 11, 00, 00, 00, time.UTC), wantErr: true},
|
||||
{cfg: boundedCfg, when: time0, want: 0},
|
||||
{cfg: boundedCfg, when: time1, want: 1},
|
||||
{cfg: boundedCfg, when: time2, want: 2},
|
||||
{cfg: boundedCfg, when: time2_5, want: 2},
|
||||
{cfg: boundedCfg, when: time3, want: 3},
|
||||
{cfg: boundedCfg, when: time4, wantErr: true},
|
||||
{cfg: boundedCfg, when: time.Date(2015, 9, 19, 11, 00, 00, 00, time.UTC), wantErr: true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
tlc, err := NewTemporalLogClient(test.cfg, nil)
|
||||
if err != nil {
|
||||
t.Errorf("NewTemporalLogClient(%+v)=nil, %v; want _,nil", test.cfg, err)
|
||||
continue
|
||||
}
|
||||
got, err := tlc.IndexByDate(test.when)
|
||||
if err != nil {
|
||||
if !test.wantErr {
|
||||
t.Errorf("NewTemporalLogClient(%+v).idxByDate()=%d,%v; want %d,nil", test.cfg, got, err, test.want)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if test.wantErr {
|
||||
t.Errorf("NewTemporalLogClient(%+v).idxByDate(%v)=%d, nil; want _, 'no log found'", test.cfg, test.when, got)
|
||||
}
|
||||
if got != test.want {
|
||||
t.Errorf("NewTemporalLogClient(%+v).idxByDate(%v)=%d, nil; want %d, nil", test.cfg, test.when, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemporalAddChain(t *testing.T) {
|
||||
hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/ct/v1/add-chain":
|
||||
data, _ := sctToJSON(testdata.TestCertProof)
|
||||
w.Write(data)
|
||||
case "/ct/v1/add-pre-chain":
|
||||
data, _ := sctToJSON(testdata.TestPreCertProof)
|
||||
w.Write(data)
|
||||
default:
|
||||
t.Fatalf("Incorrect URL path: %s", r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer hs.Close()
|
||||
|
||||
cert, err := x509util.CertificateFromPEM(testdata.TestCertPEM)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse certificate from PEM: %v", err)
|
||||
}
|
||||
certChain := []ct.ASN1Cert{{Data: cert.Raw}}
|
||||
precert, err := x509util.CertificateFromPEM(testdata.TestPreCertPEM)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse pre-certificate from PEM: %v", err)
|
||||
}
|
||||
issuer, err := x509util.CertificateFromPEM(testdata.CACertPEM)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse issuer certificate from PEM: %v", err)
|
||||
}
|
||||
precertChain := []ct.ASN1Cert{{Data: precert.Raw}, {Data: issuer.Raw}}
|
||||
// Both have Not After = Jun 1 00:00:00 2022 GMT
|
||||
ts1, _ := ptypes.TimestampProto(time.Date(2022, 5, 19, 11, 00, 00, 00, time.UTC))
|
||||
ts2, _ := ptypes.TimestampProto(time.Date(2022, 6, 19, 11, 00, 00, 00, time.UTC))
|
||||
p, _ := pem.Decode([]byte(testdata.LogPublicKeyPEM))
|
||||
if p == nil {
|
||||
t.Fatalf("Failed to parse public key from PEM: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
cfg configpb.TemporalLogConfig
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: hs.URL, NotAfterStart: nil, NotAfterLimit: nil, PublicKeyDer: p.Bytes},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: hs.URL, NotAfterStart: nil, NotAfterLimit: ts2, PublicKeyDer: p.Bytes},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: hs.URL, NotAfterStart: ts1, NotAfterLimit: nil, PublicKeyDer: p.Bytes},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: hs.URL, NotAfterStart: ts1, NotAfterLimit: ts2, PublicKeyDer: p.Bytes},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: hs.URL, NotAfterStart: nil, NotAfterLimit: ts1, PublicKeyDer: p.Bytes},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
cfg: configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{Uri: hs.URL, NotAfterStart: ts2, NotAfterLimit: nil, PublicKeyDer: p.Bytes},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
for _, test := range tests {
|
||||
tlc, err := NewTemporalLogClient(test.cfg, nil)
|
||||
if err != nil {
|
||||
t.Errorf("NewTemporalLogClient(%+v)=nil, %v; want _,nil", test.cfg, err)
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = tlc.AddChain(ctx, certChain)
|
||||
if err != nil {
|
||||
if !test.wantErr {
|
||||
t.Errorf("AddChain()=nil,%v; want sct,nil", err)
|
||||
}
|
||||
} else if test.wantErr {
|
||||
t.Errorf("AddChain()=sct,nil; want nil,_")
|
||||
}
|
||||
|
||||
_, err = tlc.AddPreChain(ctx, precertChain)
|
||||
if err != nil {
|
||||
if !test.wantErr {
|
||||
t.Errorf("AddPreChain()=nil,%v; want sct,nil", err)
|
||||
}
|
||||
} else if test.wantErr {
|
||||
t.Errorf("AddPreChain()=sct,nil; want nil,_")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemporalAddChainErrors(t *testing.T) {
|
||||
hs := serveSCTAt(t, "/ct/v1/add-chain", testdata.TestCertProof)
|
||||
defer hs.Close()
|
||||
|
||||
cfg := configpb.TemporalLogConfig{
|
||||
Shard: []*configpb.LogShardConfig{
|
||||
{
|
||||
Uri: hs.URL,
|
||||
NotAfterStart: nil,
|
||||
NotAfterLimit: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
tlc, err := NewTemporalLogClient(cfg, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("NewTemporalLogClient(%+v)=nil, %v; want _,nil", cfg, err)
|
||||
}
|
||||
|
||||
_, err = tlc.AddChain(ctx, nil)
|
||||
if err == nil {
|
||||
t.Errorf("AddChain(nil)=sct,nil; want nil, 'missing chain'")
|
||||
}
|
||||
_, err = tlc.AddChain(ctx, []ct.ASN1Cert{{Data: []byte{0x01, 0x02}}})
|
||||
if err == nil {
|
||||
t.Errorf("AddChain(nil)=sct,nil; want nil, 'failed to parse'")
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user