check hosts in ssl certificates

This commit is contained in:
Mikaël Cluseau
2018-08-09 15:07:53 +02:00
parent 481115e0d0
commit 331f9ea96c
362 changed files with 2499 additions and 59344 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,263 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package asn1
import (
"bytes"
"encoding/hex"
"math/big"
"strings"
"testing"
"time"
)
type intStruct struct {
A int
}
type twoIntStruct struct {
A int
B int
}
type bigIntStruct struct {
A *big.Int
}
type nestedStruct struct {
A intStruct
}
type rawContentsStruct struct {
Raw RawContent
A int
}
type implicitTagTest struct {
A int `asn1:"implicit,tag:5"`
}
type explicitTagTest struct {
A int `asn1:"explicit,tag:5"`
}
type flagTest struct {
A Flag `asn1:"tag:0,optional"`
}
type generalizedTimeTest struct {
A time.Time `asn1:"generalized"`
}
type ia5StringTest struct {
A string `asn1:"ia5"`
}
type printableStringTest struct {
A string `asn1:"printable"`
}
type genericStringTest struct {
A string
}
type optionalRawValueTest struct {
A RawValue `asn1:"optional"`
}
type omitEmptyTest struct {
A []string `asn1:"omitempty"`
}
type defaultTest struct {
A int `asn1:"optional,default:1"`
}
type applicationTest struct {
A int `asn1:"application,tag:0"`
B int `asn1:"application,tag:1,explicit"`
}
type numericStringTest struct {
A string `asn1:"numeric"`
}
type testAuthKeyID struct {
ID []byte `asn1:"optional,tag:0"`
Issuer RawValue `asn1:"optional,tag:1"`
SerialNumber *big.Int `asn1:"optional,tag:2"`
}
type testSET []int
var PST = time.FixedZone("PST", -8*60*60)
type marshalTest struct {
in interface{}
out string // hex encoded
}
func farFuture() time.Time {
t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
if err != nil {
panic(err)
}
return t
}
var marshalTests = []marshalTest{
{10, "02010a"},
{127, "02017f"},
{128, "02020080"},
{-128, "020180"},
{-129, "0202ff7f"},
{intStruct{64}, "3003020140"},
{bigIntStruct{big.NewInt(0x123456)}, "30050203123456"},
{twoIntStruct{64, 65}, "3006020140020141"},
{nestedStruct{intStruct{127}}, "3005300302017f"},
{[]byte{1, 2, 3}, "0403010203"},
{implicitTagTest{64}, "3003850140"},
{explicitTagTest{64}, "3005a503020140"},
{flagTest{true}, "30028000"},
{flagTest{false}, "3000"},
{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
{farFuture(), "180f32313030303430353132303130315a"},
{generalizedTimeTest{time.Unix(1258325776, 0).UTC()}, "3011180f32303039313131353232353631365a"},
{BitString{[]byte{0x80}, 1}, "03020780"},
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
{ObjectIdentifier([]int{1, 2, 840, 133549, 1, 1, 5}), "06092a864888932d010105"},
{ObjectIdentifier([]int{2, 100, 3}), "0603813403"},
{"test", "130474657374"},
{
"" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // This is 127 times 'x'
"137f" +
"7878787878787878787878787878787878787878787878787878787878787878" +
"7878787878787878787878787878787878787878787878787878787878787878" +
"7878787878787878787878787878787878787878787878787878787878787878" +
"78787878787878787878787878787878787878787878787878787878787878",
},
{
"" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // This is 128 times 'x'
"138180" +
"7878787878787878787878787878787878787878787878787878787878787878" +
"7878787878787878787878787878787878787878787878787878787878787878" +
"7878787878787878787878787878787878787878787878787878787878787878" +
"7878787878787878787878787878787878787878787878787878787878787878",
},
{ia5StringTest{"test"}, "3006160474657374"},
{optionalRawValueTest{}, "3000"},
{printableStringTest{"test"}, "3006130474657374"},
{printableStringTest{"test*"}, "30071305746573742a"},
{genericStringTest{"test"}, "3006130474657374"},
{genericStringTest{"test*"}, "30070c05746573742a"},
{genericStringTest{"test&"}, "30070c057465737426"},
{rawContentsStruct{nil, 64}, "3003020140"},
{rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
{RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
{testSET([]int{10}), "310302010a"},
{omitEmptyTest{[]string{}}, "3000"},
{omitEmptyTest{[]string{"1"}}, "30053003130131"},
{"Σ", "0c02cea3"},
{defaultTest{0}, "3003020100"},
{defaultTest{1}, "3000"},
{defaultTest{2}, "3003020102"},
{applicationTest{1, 2}, "30084001016103020102"},
{numericStringTest{"1 9"}, "30051203312039"},
{testAuthKeyID{ID: []byte{0x01, 0x02, 0x03, 0x04}, SerialNumber: big.NewInt(0x12233445566)}, "300e8004010203048206012233445566"},
{testAuthKeyID{ID: []byte{0x01, 0x02, 0x03, 0x04}}, "3006800401020304"},
}
func TestMarshal(t *testing.T) {
for i, test := range marshalTests {
data, err := Marshal(test.in)
if err != nil {
t.Errorf("#%d failed: %s", i, err)
}
out, _ := hex.DecodeString(test.out)
if !bytes.Equal(out, data) {
t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out)
}
}
}
type marshalWithParamsTest struct {
in interface{}
params string
out string // hex encoded
}
var marshalWithParamsTests = []marshalWithParamsTest{
{intStruct{10}, "set", "310302010a"},
{intStruct{10}, "application", "600302010a"},
}
func TestMarshalWithParams(t *testing.T) {
for i, test := range marshalWithParamsTests {
data, err := MarshalWithParams(test.in, test.params)
if err != nil {
t.Errorf("#%d failed: %s", i, err)
}
out, _ := hex.DecodeString(test.out)
if !bytes.Equal(out, data) {
t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out)
}
}
}
type marshalErrTest struct {
in interface{}
err string
}
var marshalErrTests = []marshalErrTest{
{bigIntStruct{nil}, "empty integer"},
{numericStringTest{"a"}, "invalid character"},
{ia5StringTest{"\xb0"}, "invalid character"},
{printableStringTest{"!"}, "invalid character"},
}
func TestMarshalError(t *testing.T) {
for i, test := range marshalErrTests {
_, err := Marshal(test.in)
if err == nil {
t.Errorf("#%d should fail, but success", i)
continue
}
if !strings.Contains(err.Error(), test.err) {
t.Errorf("#%d got: %v want %v", i, err, test.err)
}
}
}
func TestInvalidUTF8(t *testing.T) {
_, err := Marshal(string([]byte{0xff, 0xff}))
if err == nil {
t.Errorf("invalid UTF8 string was accepted")
}
}
func BenchmarkMarshal(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for _, test := range marshalTests {
Marshal(test.in)
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,482 +0,0 @@
// 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_test
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"
"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 := client.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 := client.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([]byte(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([]byte(testdata.TestPreCertPEM))
if err != nil {
t.Fatalf("Failed to parse pre-certificate from PEM: %v", err)
}
issuer, err := x509util.CertificateFromPEM([]byte(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 := client.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 := client.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'")
}
}

View File

@ -1,37 +0,0 @@
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

@ -1,32 +0,0 @@
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

@ -1,17 +0,0 @@
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

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

View File

@ -1,27 +0,0 @@
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

@ -1,13 +0,0 @@
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

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

View File

@ -1,13 +0,0 @@
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

@ -1,19 +0,0 @@
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

@ -1,19 +0,0 @@
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

@ -1,20 +0,0 @@
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

@ -1,22 +0,0 @@
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

@ -1,15 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -1,15 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -1,12 +0,0 @@
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

@ -1,18 +0,0 @@
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

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

View File

@ -1,28 +0,0 @@
# 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

@ -1,22 +0,0 @@
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

@ -1,19 +0,0 @@
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

@ -1,91 +0,0 @@
// 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

@ -1,150 +0,0 @@
// 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

@ -1,117 +0,0 @@
// 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 jsonclient
import (
"math"
"testing"
"time"
)
const testLeeway = 25 * time.Microsecond
func fuzzyTimeEquals(a, b time.Time, leeway time.Duration) bool {
diff := math.Abs(float64(a.Sub(b).Nanoseconds()))
if diff < float64(leeway.Nanoseconds()) {
return true
}
return false
}
func fuzzyDurationEquals(a, b time.Duration, leeway time.Duration) bool {
diff := math.Abs(float64(a.Nanoseconds() - b.Nanoseconds()))
if diff < float64(leeway.Nanoseconds()) {
return true
}
return false
}
func TestBackoff(t *testing.T) {
b := backoff{}
// Test that the interval increases as expected
for i := uint(0); i < maxMultiplier; i++ {
n := time.Now()
interval := b.set(nil)
if interval != time.Second*(1<<i) {
t.Fatalf("backoff.set(nil)=%v; want %v", interval, time.Second*(1<<i))
}
expected := n.Add(interval)
until := b.until()
if !fuzzyTimeEquals(expected, until, time.Millisecond) {
t.Fatalf("backoff.until()=%v; want %v (+ 0-250ms)", expected, until)
}
// reset notBefore
b.notBefore = time.Time{}
}
// Test that multiplier doesn't go above maxMultiplier
b.multiplier = maxMultiplier
b.notBefore = time.Time{}
interval := b.set(nil)
if b.multiplier > maxMultiplier {
t.Fatalf("backoff.multiplier=%v; want %v", b.multiplier, maxMultiplier)
}
if interval > time.Second*(1<<(maxMultiplier-1)) {
t.Fatalf("backoff.set(nil)=%v; want %v", interval, 1<<(maxMultiplier-1)*time.Second)
}
// Test decreaseMultiplier properly decreases the multiplier
b.multiplier = 1
b.notBefore = time.Time{}
b.decreaseMultiplier()
if b.multiplier != 0 {
t.Fatalf("backoff.multiplier=%v; want %v", b.multiplier, 0)
}
// Test decreaseMultiplier doesn't reduce multiplier below 0
b.decreaseMultiplier()
if b.multiplier != 0 {
t.Fatalf("backoff.multiplier=%v; want %v", b.multiplier, 0)
}
}
func TestBackoffOverride(t *testing.T) {
b := backoff{}
for _, tc := range []struct {
notBefore time.Time
override time.Duration
expectedInterval time.Duration
}{
{
notBefore: time.Now().Add(time.Hour),
override: time.Second * 1800,
expectedInterval: time.Hour,
},
{
notBefore: time.Now().Add(time.Hour),
override: time.Second * 7200,
expectedInterval: 2 * time.Hour,
},
{
notBefore: time.Time{},
override: time.Second * 7200,
expectedInterval: 2 * time.Hour,
},
} {
b.multiplier = 0
b.notBefore = tc.notBefore
interval := b.set(&tc.override)
if !fuzzyDurationEquals(tc.expectedInterval, interval, testLeeway) {
t.Fatalf("backoff.set(%v)=%v; want %v", tc.override, interval, tc.expectedInterval)
}
}
}

View File

@ -1,446 +0,0 @@
// 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 jsonclient
import (
"context"
"encoding/json"
"encoding/pem"
"fmt"
"net/http"
"net/http/httptest"
"reflect"
"regexp"
"strconv"
"strings"
"sync"
"testing"
"time"
"github.com/google/certificate-transparency-go/testdata"
)
func publicKeyPEMToDER(key string) []byte {
block, _ := pem.Decode([]byte(key))
if block == nil {
panic("failed to decode public key PEM")
}
if block.Type != "PUBLIC KEY" {
panic("PEM does not have type 'PUBLIC KEY'")
}
return block.Bytes
}
func TestNewJSONClient(t *testing.T) {
tests := []struct {
name string
opts Options
errstr string
}{
{
name: "invalid PublicKey",
opts: Options{PublicKey: "bogus"},
errstr: "no PEM block",
},
{
name: "invalid PublicKeyDER",
opts: Options{PublicKeyDER: []byte("bogus")},
errstr: "asn1: structure error",
},
{
name: "RSA PublicKey",
opts: Options{PublicKey: testdata.RsaPublicKeyPEM},
},
{
name: "RSA PublicKeyDER",
opts: Options{PublicKeyDER: publicKeyPEMToDER(testdata.RsaPublicKeyPEM)},
},
{
name: "ECDSA PublicKey",
opts: Options{PublicKey: testdata.EcdsaPublicKeyPEM},
},
{
name: "ECDSA PublicKeyDER",
opts: Options{PublicKeyDER: publicKeyPEMToDER(testdata.EcdsaPublicKeyPEM)},
},
{
name: "DSA PublicKey",
opts: Options{PublicKey: testdata.DsaPublicKeyPEM},
errstr: "Unsupported public key type",
},
{
name: "DSA PublicKeyDER",
opts: Options{PublicKeyDER: publicKeyPEMToDER(testdata.DsaPublicKeyPEM)},
errstr: "Unsupported public key type",
},
{
name: "PublicKey contains trailing garbage",
opts: Options{PublicKey: testdata.RsaPublicKeyPEM + "bogus"},
errstr: "extra data found",
},
{
name: "PublicKeyDER contains trailing garbage",
opts: Options{PublicKeyDER: append(publicKeyPEMToDER(testdata.RsaPublicKeyPEM), []byte("deadbeef")...)},
errstr: "trailing data",
},
}
for _, test := range tests {
client, err := New("http://127.0.0.1", nil, test.opts)
if test.errstr != "" {
if err == nil {
t.Errorf("%v: New()=%p,nil; want error %q", test.name, client, test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("%v: New()=nil,%q; want error %q", test.name, err, test.errstr)
}
continue
}
if err != nil {
t.Errorf("%v: New()=nil,%q; want no error", test.name, err)
} else if client == nil {
t.Errorf("%v: New()=nil,nil; want client", test.name)
}
}
}
type TestStruct struct {
TreeSize int `json:"tree_size"`
Timestamp int `json:"timestamp"`
Data string `json:"data"`
}
type TestParams struct {
RespCode int `json:"rc"`
}
func MockServer(t *testing.T, failCount int, retryAfter int) *httptest.Server {
t.Helper()
mu := sync.Mutex{}
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
switch r.URL.Path {
case "/struct/path":
fmt.Fprintf(w, `{"tree_size": 11, "timestamp": 99}`)
case "/struct/params":
var s TestStruct
if r.Method == http.MethodGet {
s.TreeSize, _ = strconv.Atoi(r.FormValue("tree_size"))
s.Timestamp, _ = strconv.Atoi(r.FormValue("timestamp"))
s.Data = r.FormValue("data")
} else {
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&s)
if err != nil {
panic("Failed to decode: " + err.Error())
}
defer r.Body.Close()
}
fmt.Fprintf(w, `{"tree_size": %d, "timestamp": %d, "data": "%s"}`, s.TreeSize, s.Timestamp, s.Data)
case "/error":
var params TestParams
if r.Method == http.MethodGet {
params.RespCode, _ = strconv.Atoi(r.FormValue("rc"))
} else {
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&params)
if err != nil {
panic("Failed to decode: " + err.Error())
}
defer r.Body.Close()
}
http.Error(w, "error page", params.RespCode)
case "/malformed":
fmt.Fprintf(w, `{"tree_size": 11, "timestamp": 99`) // no closing }
case "/retry":
if failCount > 0 {
failCount--
if retryAfter != 0 {
if retryAfter > 0 {
w.Header().Add("Retry-After", strconv.Itoa(retryAfter))
}
w.WriteHeader(http.StatusServiceUnavailable)
} else {
w.WriteHeader(http.StatusRequestTimeout)
}
} else {
fmt.Fprintf(w, `{"tree_size": 11, "timestamp": 99}`)
}
case "/retry-rfc1123":
if failCount > 0 {
failCount--
w.Header().Add("Retry-After", time.Now().Add(time.Duration(retryAfter)*time.Second).Format(time.RFC1123))
w.WriteHeader(http.StatusServiceUnavailable)
} else {
fmt.Fprintf(w, `{"tree_size": 11, "timestamp": 99}`)
}
default:
t.Fatalf("Unhandled URL path: %s", r.URL.Path)
}
}))
}
func TestGetAndParse(t *testing.T) {
rc := regexp.MustCompile
tests := []struct {
uri string
params map[string]string
status int
result TestStruct
errstr *regexp.Regexp
wantBody bool
}{
{uri: "/short%", errstr: rc("invalid URL escape")},
{uri: "/malformed", status: http.StatusOK, errstr: rc("unexpected EOF"), wantBody: true},
{uri: "/error", params: map[string]string{"rc": "404"}, status: http.StatusNotFound, wantBody: true},
{uri: "/error", params: map[string]string{"rc": "403"}, status: http.StatusForbidden, wantBody: true},
{uri: "/struct/path", status: http.StatusOK, result: TestStruct{11, 99, ""}, wantBody: true},
{
uri: "/struct/params",
status: http.StatusOK,
params: map[string]string{"tree_size": "42", "timestamp": "88", "data": "abcd"},
result: TestStruct{42, 88, "abcd"},
wantBody: true,
},
}
ts := MockServer(t, -1, 0)
defer ts.Close()
logClient, err := New(ts.URL, &http.Client{}, Options{})
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
for _, test := range tests {
var result TestStruct
httpRsp, body, err := logClient.GetAndParse(ctx, test.uri, test.params, &result)
if gotBody := (body != nil); gotBody != test.wantBody {
t.Errorf("GetAndParse(%q) got body? %v, want? %v", test.uri, gotBody, test.wantBody)
}
if test.errstr != nil {
if err == nil {
t.Errorf("GetAndParse(%q)=%+v,_,nil; want error matching %q", test.uri, result, test.errstr)
} else if !test.errstr.MatchString(err.Error()) {
t.Errorf("GetAndParse(%q)=nil,_,%q; want error matching %q", test.uri, err.Error(), test.errstr)
}
continue
}
if httpRsp.StatusCode != test.status {
t.Errorf("GetAndParse('%s') got status %d; want %d", test.uri, httpRsp.StatusCode, test.status)
}
if test.status == http.StatusOK {
if err != nil {
t.Errorf("GetAndParse(%q)=nil,_,%q; want %+v", test.uri, err.Error(), result)
}
if !reflect.DeepEqual(result, test.result) {
t.Errorf("GetAndParse(%q)=%+v,_,nil; want %+v", test.uri, result, test.result)
}
}
}
}
func TestPostAndParse(t *testing.T) {
rc := regexp.MustCompile
tests := []struct {
uri string
request interface{}
status int
result TestStruct
errstr *regexp.Regexp
wantBody bool
}{
{uri: "/short%", errstr: rc("invalid URL escape")},
{uri: "/struct/params", request: json.Number(`invalid`), errstr: rc("invalid number literal")},
{uri: "/malformed", status: http.StatusOK, errstr: rc("unexpected end of JSON"), wantBody: true},
{uri: "/error", request: TestParams{RespCode: 404}, status: http.StatusNotFound, wantBody: true},
{uri: "/error", request: TestParams{RespCode: 403}, status: http.StatusForbidden, wantBody: true},
{uri: "/struct/path", status: http.StatusOK, result: TestStruct{11, 99, ""}, wantBody: true},
{
uri: "/struct/params",
status: http.StatusOK,
request: TestStruct{42, 88, "abcd"},
result: TestStruct{42, 88, "abcd"},
wantBody: true,
},
}
ts := MockServer(t, -1, 0)
defer ts.Close()
logClient, err := New(ts.URL, &http.Client{}, Options{})
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
for _, test := range tests {
var result TestStruct
httpRsp, body, err := logClient.PostAndParse(ctx, test.uri, test.request, &result)
if gotBody := (body != nil); gotBody != test.wantBody {
t.Errorf("GetAndParse(%q) returned body %v, wanted %v", test.uri, gotBody, test.wantBody)
}
if test.errstr != nil {
if err == nil {
t.Errorf("PostAndParse(%q)=%+v,nil; want error matching %q", test.uri, result, test.errstr)
} else if !test.errstr.MatchString(err.Error()) {
t.Errorf("PostAndParse(%q)=nil,%q; want error matching %q", test.uri, err.Error(), test.errstr)
}
continue
}
if httpRsp.StatusCode != test.status {
t.Errorf("PostAndParse(%q) got status %d; want %d", test.uri, httpRsp.StatusCode, test.status)
}
if test.status == http.StatusOK {
if err != nil {
t.Errorf("PostAndParse(%q)=nil,%q; want %+v", test.uri, err.Error(), test.result)
}
if !reflect.DeepEqual(result, test.result) {
t.Errorf("PostAndParse(%q)=%+v,nil; want %+v", test.uri, result, test.result)
}
}
}
}
// mockBackoff is not safe for concurrent usage
type mockBackoff struct {
override time.Duration
}
func (mb *mockBackoff) set(o *time.Duration) time.Duration {
if o != nil {
mb.override = *o
}
return 0
}
func (mb *mockBackoff) decreaseMultiplier() {}
func (mb *mockBackoff) until() time.Time { return time.Time{} }
func TestPostAndParseWithRetry(t *testing.T) {
tests := []struct {
uri string
request interface{}
deadlineSecs int // -1 indicates no deadline
retryAfter int // -1 indicates generate 503 with no Retry-After
failCount int
errstr string
expectedBackoff time.Duration // 0 indicates no expected backoff override set
}{
{
uri: "/error",
request: TestParams{RespCode: 418},
deadlineSecs: -1,
retryAfter: 0,
failCount: 0,
errstr: "teapot",
expectedBackoff: 0,
},
{
uri: "/short%",
request: nil,
deadlineSecs: 0,
retryAfter: 0,
failCount: 0,
errstr: "deadline exceeded",
expectedBackoff: 0,
},
{
uri: "/retry",
request: nil,
deadlineSecs: -1,
retryAfter: 0,
failCount: 1,
errstr: "",
expectedBackoff: 0,
},
{
uri: "/retry",
request: nil,
deadlineSecs: -1,
retryAfter: 5,
failCount: 1,
errstr: "",
expectedBackoff: 5 * time.Second,
},
{
uri: "/retry-rfc1123",
request: nil,
deadlineSecs: -1,
retryAfter: 5,
failCount: 1,
errstr: "",
expectedBackoff: 5 * time.Second,
},
}
for _, test := range tests {
ts := MockServer(t, test.failCount, test.retryAfter)
defer ts.Close()
logClient, err := New(ts.URL, &http.Client{}, Options{})
if err != nil {
t.Fatal(err)
}
mb := mockBackoff{}
logClient.backoff = &mb
ctx := context.Background()
if test.deadlineSecs >= 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(context.Background(), time.Now().Add(time.Duration(test.deadlineSecs)*time.Second))
defer cancel()
}
var result TestStruct
httpRsp, _, err := logClient.PostAndParseWithRetry(ctx, test.uri, test.request, &result)
if test.errstr != "" {
if err == nil {
t.Errorf("PostAndParseWithRetry()=%+v,nil; want error %q", result, test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("PostAndParseWithRetry()=nil,%q; want error %q", err.Error(), test.errstr)
}
continue
}
if err != nil {
t.Errorf("PostAndParseWithRetry()=nil,%q; want no error", err.Error())
} else if httpRsp.StatusCode != http.StatusOK {
t.Errorf("PostAndParseWithRetry() got status %d; want OK(404)", httpRsp.StatusCode)
}
if test.expectedBackoff > 0 && !fuzzyDurationEquals(test.expectedBackoff, mb.override, time.Second) {
t.Errorf("Unexpected backoff override set: got: %s, wanted: %s", mb.override, test.expectedBackoff)
}
}
}
func TestContextRequired(t *testing.T) {
ts := MockServer(t, -1, 0)
defer ts.Close()
logClient, err := New(ts.URL, &http.Client{}, Options{})
if err != nil {
t.Fatal(err)
}
var result TestStruct
_, _, err = logClient.GetAndParse(nil, "/struct/path", nil, &result)
if err == nil {
t.Errorf("GetAndParse() succeeded with empty Context")
}
_, _, err = logClient.PostAndParse(nil, "/struct/path", nil, &result)
if err == nil {
t.Errorf("PostAndParse() succeeded with empty Context")
}
_, _, err = logClient.PostAndParseWithRetry(nil, "/struct/path", nil, &result)
if err == nil {
t.Errorf("PostAndParseWithRetry() succeeded with empty Context")
}
}

View File

@ -1,513 +0,0 @@
// Copyright 2015 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 ct
import (
"bytes"
"encoding/hex"
"encoding/pem"
"io/ioutil"
"reflect"
"strings"
"testing"
"github.com/google/certificate-transparency-go/tls"
)
func dh(h string) []byte {
r, err := hex.DecodeString(h)
if err != nil {
panic(err)
}
return r
}
const (
defaultSCTLogIDString string = "iamapublickeyshatwofivesixdigest"
defaultSCTTimestamp uint64 = 1234
defaultSCTSignatureString string = "\x04\x03\x00\x09signature"
defaultCertifictateString string = "certificate"
defaultPrecertString string = "precert"
defaultPrecertIssuerHashString string = "iamapublickeyshatwofivesixdigest"
defaultPrecertTBSString string = "tbs"
defaultCertificateSCTSignatureInputHexString string =
// version, 1 byte
"00" +
// signature type, 1 byte
"00" +
// timestamp, 8 bytes
"00000000000004d2" +
// entry type, 2 bytes
"0000" +
// leaf certificate length, 3 bytes
"00000b" +
// leaf certificate, 11 bytes
"6365727469666963617465" +
// extensions length, 2 bytes
"0000" +
// extensions, 0 bytes
""
defaultPrecertSCTSignatureInputHexString string =
// version, 1 byte
"00" +
// signature type, 1 byte
"00" +
// timestamp, 8 bytes
"00000000000004d2" +
// entry type, 2 bytes
"0001" +
// issuer key hash, 32 bytes
"69616d617075626c69636b657973686174776f66697665736978646967657374" +
// tbs certificate length, 3 bytes
"000003" +
// tbs certificate, 3 bytes
"746273" +
// extensions length, 2 bytes
"0000" +
// extensions, 0 bytes
""
defaultSTHSignedHexString string =
// version, 1 byte
"00" +
// signature type, 1 byte
"01" +
// timestamp, 8 bytes
"0000000000000929" +
// tree size, 8 bytes
"0000000000000006" +
// root hash, 32 bytes
"696d757374626565786163746c7974686972747974776f62797465736c6f6e67"
defaultSCTHexString string =
// version, 1 byte
"00" +
// keyid, 32 bytes
"69616d617075626c69636b657973686174776f66697665736978646967657374" +
// timestamp, 8 bytes
"00000000000004d2" +
// extensions length, 2 bytes
"0000" +
// extensions, 0 bytes
// hash algo, sig algo, 2 bytes
"0403" +
// signature length, 2 bytes
"0009" +
// signature, 9 bytes
"7369676e6174757265"
defaultSCTListHexString string = "0476007400380069616d617075626c69636b657973686174776f6669766573697864696765737400000000000004d20000040300097369676e617475726500380069616d617075626c69636b657973686174776f6669766573697864696765737400000000000004d20000040300097369676e6174757265"
)
func defaultSCTLogID() LogID {
var id LogID
copy(id.KeyID[:], defaultSCTLogIDString)
return id
}
func defaultSCTSignature() DigitallySigned {
var ds DigitallySigned
if _, err := tls.Unmarshal([]byte(defaultSCTSignatureString), &ds); err != nil {
panic(err)
}
return ds
}
func defaultSCT() SignedCertificateTimestamp {
return SignedCertificateTimestamp{
SCTVersion: V1,
LogID: defaultSCTLogID(),
Timestamp: defaultSCTTimestamp,
Extensions: []byte{},
Signature: defaultSCTSignature()}
}
func defaultCertificate() []byte {
return []byte(defaultCertifictateString)
}
func defaultExtensions() []byte {
return []byte{}
}
func defaultCertificateSCTSignatureInput(t *testing.T) []byte {
t.Helper()
r, err := hex.DecodeString(defaultCertificateSCTSignatureInputHexString)
if err != nil {
t.Fatalf("failed to decode defaultCertificateSCTSignatureInputHexString: %v", err)
}
return r
}
func defaultCertificateLogEntry() LogEntry {
return LogEntry{
Index: 1,
Leaf: MerkleTreeLeaf{
Version: V1,
LeafType: TimestampedEntryLeafType,
TimestampedEntry: &TimestampedEntry{
Timestamp: defaultSCTTimestamp,
EntryType: X509LogEntryType,
X509Entry: &ASN1Cert{Data: defaultCertificate()},
},
},
}
}
func defaultPrecertSCTSignatureInput(t *testing.T) []byte {
t.Helper()
r, err := hex.DecodeString(defaultPrecertSCTSignatureInputHexString)
if err != nil {
t.Fatalf("failed to decode defaultPrecertSCTSignatureInputHexString: %v", err)
}
return r
}
func defaultPrecertTBS() []byte {
return []byte(defaultPrecertTBSString)
}
func defaultPrecertIssuerHash() [32]byte {
var b [32]byte
copy(b[:], []byte(defaultPrecertIssuerHashString))
return b
}
func defaultPrecertLogEntry() LogEntry {
return LogEntry{
Index: 1,
Leaf: MerkleTreeLeaf{
Version: V1,
LeafType: TimestampedEntryLeafType,
TimestampedEntry: &TimestampedEntry{
Timestamp: defaultSCTTimestamp,
EntryType: PrecertLogEntryType,
PrecertEntry: &PreCert{
IssuerKeyHash: defaultPrecertIssuerHash(),
TBSCertificate: defaultPrecertTBS(),
},
},
},
}
}
func defaultSTH() SignedTreeHead {
var root SHA256Hash
copy(root[:], "imustbeexactlythirtytwobyteslong")
return SignedTreeHead{
TreeSize: 6,
Timestamp: 2345,
SHA256RootHash: root,
TreeHeadSignature: DigitallySigned{
Algorithm: tls.SignatureAndHashAlgorithm{
Hash: tls.SHA256,
Signature: tls.ECDSA},
Signature: []byte("tree_signature"),
},
}
}
//////////////////////////////////////////////////////////////////////////////////
// Tests start here:
//////////////////////////////////////////////////////////////////////////////////
func TestSerializeV1SCTSignatureInputForCertificateKAT(t *testing.T) {
serialized, err := SerializeSCTSignatureInput(defaultSCT(), defaultCertificateLogEntry())
if err != nil {
t.Fatalf("Failed to serialize SCT for signing: %v", err)
}
if bytes.Compare(serialized, defaultCertificateSCTSignatureInput(t)) != 0 {
t.Fatalf("Serialized certificate signature input doesn't match expected answer:\n%v\n%v", serialized, defaultCertificateSCTSignatureInput(t))
}
}
func TestSerializeV1SCTSignatureInputForPrecertKAT(t *testing.T) {
serialized, err := SerializeSCTSignatureInput(defaultSCT(), defaultPrecertLogEntry())
if err != nil {
t.Fatalf("Failed to serialize SCT for signing: %v", err)
}
if bytes.Compare(serialized, defaultPrecertSCTSignatureInput(t)) != 0 {
t.Fatalf("Serialized precertificate signature input doesn't match expected answer:\n%v\n%v", serialized, defaultPrecertSCTSignatureInput(t))
}
}
func TestSerializeV1SCTJSONSignature(t *testing.T) {
entry := LogEntry{Leaf: *CreateJSONMerkleTreeLeaf("data", defaultSCT().Timestamp)}
expected := dh(
// version, 1 byte
"00" +
// signature type, 1 byte
"00" +
// timestamp, 8 bytes
"00000000000004d2" +
// entry type, 2 bytes
"8000" +
// tbs certificate length, 18 bytes
"000012" +
// { "data": "data" }, 3 bytes
"7b202264617461223a20226461746122207d" +
// extensions length, 2 bytes
"0000" +
// extensions, 0 bytes
"")
serialized, err := SerializeSCTSignatureInput(defaultSCT(), entry)
if err != nil {
t.Fatalf("Failed to serialize SCT for signing: %v", err)
}
if !bytes.Equal(serialized, expected) {
t.Fatalf("Serialized JSON signature :\n%x, want\n%x", serialized, expected)
}
}
func TestSerializeV1STHSignatureKAT(t *testing.T) {
b, err := SerializeSTHSignatureInput(defaultSTH())
if err != nil {
t.Fatalf("Failed to serialize defaultSTH: %v", err)
}
if bytes.Compare(b, mustDehex(t, defaultSTHSignedHexString)) != 0 {
t.Fatalf("defaultSTH incorrectly serialized, expected:\n%v\ngot:\n%v", mustDehex(t, defaultSTHSignedHexString), b)
}
}
func TestMarshalDigitallySigned(t *testing.T) {
b, err := tls.Marshal(
DigitallySigned{
Algorithm: tls.SignatureAndHashAlgorithm{
Hash: tls.SHA512,
Signature: tls.ECDSA},
Signature: []byte("signature")})
if err != nil {
t.Fatalf("Failed to marshal DigitallySigned struct: %v", err)
}
if b[0] != byte(tls.SHA512) {
t.Fatalf("Expected b[0] == SHA512, but found %v", tls.HashAlgorithm(b[0]))
}
if b[1] != byte(tls.ECDSA) {
t.Fatalf("Expected b[1] == ECDSA, but found %v", tls.SignatureAlgorithm(b[1]))
}
if b[2] != 0x00 || b[3] != 0x09 {
t.Fatalf("Found incorrect length bytes, expected (0x00, 0x09) found %v", b[2:3])
}
if string(b[4:]) != "signature" {
t.Fatalf("Found incorrect signature bytes, expected %v, found %v", []byte("signature"), b[4:])
}
}
func TestUnmarshalDigitallySigned(t *testing.T) {
var ds DigitallySigned
if _, err := tls.Unmarshal([]byte("\x01\x02\x00\x0aSiGnAtUrE!"), &ds); err != nil {
t.Fatalf("Failed to unmarshal DigitallySigned: %v", err)
}
if ds.Algorithm.Hash != tls.MD5 {
t.Fatalf("Expected HashAlgorithm %v, but got %v", tls.MD5, ds.Algorithm.Hash)
}
if ds.Algorithm.Signature != tls.DSA {
t.Fatalf("Expected SignatureAlgorithm %v, but got %v", tls.DSA, ds.Algorithm.Signature)
}
if string(ds.Signature) != "SiGnAtUrE!" {
t.Fatalf("Expected Signature %v, but got %v", []byte("SiGnAtUrE!"), ds.Signature)
}
}
func TestMarshalUnmarshalSCTRoundTrip(t *testing.T) {
sctIn := defaultSCT()
b, err := tls.Marshal(sctIn)
if err != nil {
t.Fatalf("tls.Marshal(SCT)=nil,%v; want no error", err)
}
var sctOut SignedCertificateTimestamp
if _, err := tls.Unmarshal(b, &sctOut); err != nil {
t.Errorf("tls.Unmarshal(%s)=nil,%v; want %+v,nil", hex.EncodeToString(b), err, sctIn)
} else if !reflect.DeepEqual(sctIn, sctOut) {
t.Errorf("tls.Unmarshal(%s)=%v,nil; want %+v,nil", hex.EncodeToString(b), sctOut, sctIn)
}
}
func TestMarshalSCT(t *testing.T) {
b, err := tls.Marshal(defaultSCT())
if err != nil {
t.Errorf("tls.Marshal(defaultSCT)=nil,%v; want %s", err, defaultSCTHexString)
} else if !bytes.Equal(dh(defaultSCTHexString), b) {
t.Errorf("tls.Marshal(defaultSCT)=%s,nil; want %s", hex.EncodeToString(b), defaultSCTHexString)
}
}
func TestUnmarshalSCT(t *testing.T) {
want := defaultSCT()
var got SignedCertificateTimestamp
if _, err := tls.Unmarshal(dh(defaultSCTHexString), &got); err != nil {
t.Errorf("tls.Unmarshal(%s)=nil,%v; want %+v,nil", defaultSCTHexString, err, want)
} else if !reflect.DeepEqual(got, want) {
t.Errorf("tls.Unmarshal(%s)=%+v,nil; want %+v,nil", defaultSCTHexString, got, want)
}
}
func TestX509MerkleTreeLeafHash(t *testing.T) {
certFile := "./testdata/test-cert.pem"
sctFile := "./testdata/test-cert.proof"
certB, err := ioutil.ReadFile(certFile)
if err != nil {
t.Fatalf("Failed to read file %s: %v", certFile, err)
}
certDER, _ := pem.Decode(certB)
sctB, err := ioutil.ReadFile(sctFile)
if err != nil {
t.Fatalf("Failed to read file %s: %v", sctFile, err)
}
var sct SignedCertificateTimestamp
if _, err := tls.Unmarshal(sctB, &sct); err != nil {
t.Fatalf("Failed to deserialize SCT: %v", err)
}
leaf := CreateX509MerkleTreeLeaf(ASN1Cert{Data: certDER.Bytes}, sct.Timestamp)
b, err := tls.Marshal(*leaf)
if err != nil {
t.Fatalf("Failed to Serialize x509 leaf: %v", err)
}
leafBytes := dh("00000000013ddb27ded900000002ce308202ca30820233a003020102020106300d06092a864886f70d01010505003055310b300906035504061302474231243022060355040a131b4365727469666963617465205472616e73706172656e6379204341310e300c0603550408130557616c65733110300e060355040713074572772057656e301e170d3132303630313030303030305a170d3232303630313030303030305a3052310b30090603550406130247423121301f060355040a13184365727469666963617465205472616e73706172656e6379310e300c0603550408130557616c65733110300e060355040713074572772057656e30819f300d06092a864886f70d010101050003818d0030818902818100b1fa37936111f8792da2081c3fe41925008531dc7f2c657bd9e1de4704160b4c9f19d54ada4470404c1c51341b8f1f7538dddd28d9aca48369fc5646ddcc7617f8168aae5b41d43331fca2dadfc804d57208949061f9eef902ca47ce88c644e000f06eeeccabdc9dd2f68a22ccb09dc76e0dbc73527765b1a37a8c676253dcc10203010001a381ac3081a9301d0603551d0e041604146a0d982a3b62c44b6d2ef4e9bb7a01aa9cb798e2307d0603551d230476307480145f9d880dc873e654d4f80dd8e6b0c124b447c355a159a4573055310b300906035504061302474231243022060355040a131b4365727469666963617465205472616e73706172656e6379204341310e300c0603550408130557616c65733110300e060355040713074572772057656e82010030090603551d1304023000300d06092a864886f70d010105050003818100171cd84aac414a9a030f22aac8f688b081b2709b848b4e5511406cd707fed028597a9faefc2eee2978d633aaac14ed3235197da87e0f71b8875f1ac9e78b281749ddedd007e3ecf50645f8cbf667256cd6a1647b5e13203bb8582de7d6696f656d1c60b95f456b7fcf338571908f1c69727d24c4fccd249295795814d1dac0e60000")
if !bytes.Equal(b, leafBytes) {
t.Errorf("CreateX509MerkleTreeLeaf(): got\n %x, want\n%x", b, sctB)
}
}
func TestJSONMerkleTreeLeaf(t *testing.T) {
data := `CioaINV25GV8X4a6M6Q10avSLP9PYd5N8MwWxQvWU7E2CzZ8IgYI0KnavAUSWAoIZDc1NjMzMzMSTAgEEAMaRjBEAiBQlnp6Q3di86g8M3l5gz+9qls/Cz1+KJ+tK/jpaBtUCgIgXaJ94uLsnChA1NY7ocGwKrQwPU688hwaZ5L/DboV4mQ=2`
timestamp := uint64(1469664866615)
leaf := CreateJSONMerkleTreeLeaf(data, timestamp)
b, err := tls.Marshal(*leaf)
if err != nil {
t.Fatalf("Failed to Serialize x509 leaf: %v", err)
}
leafBytes := dh("0000000001562eda313780000000c67b202264617461223a202243696f61494e563235475638583461364d365131306176534c5039505964354e384d77577851765755374532437a5a3849675949304b6e617641555357416f495a4463314e6a4d7a4d7a4d535441674545414d61526a4245416942516c6e703651336469383667384d336c35677a2b39716c735c2f437a312b4b4a2b744b5c2f6a70614274554367496758614a3934754c736e436841314e59376f6347774b72517750553638386877615a354c5c2f44626f56346d513d3222207d0000")
if !bytes.Equal(b, leafBytes) {
t.Errorf("CreateJSONMerkleTreeLeaf(): got\n%x, want\n%x", b, leafBytes)
}
}
func TestLogEntryFromLeaf(t *testing.T) {
const (
// Cert example taken from entry #1 in argon2018 log
leafDER = "308204ef308202d7a00302010202070556658a503cca300d06092a864886f70d01010b0500307f310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793123302106035504030c1a4d657267652044656c617920496e7465726d6564696174652031301e170d3137303831303132343331355a170d3138303333313038333231375a3063310b3009060355040613024742310f300d06035504070c064c6f6e646f6e31283026060355040a0c1f476f6f676c65204365727469666963617465205472616e73706172656e637931193017060355040513103135303233363839393537353331363230820122300d06092a864886f70d01010105000382010f003082010a0282010100a2fb53365dfbcefea77e1d65bc40f34f7919fcae85d82d3003428199f0c893fca95ba139156fd5e9a3bd84dc6dab8e74151fde6dd25b31526c85719bbf8990f3d6b21bb7f321306f6ddc50b96e8917fa103b388a00e1e954ee0232a9f9fb2efa8c9f9196a7fe84dad1f66b5d36127c71c9dcf25a04acd7bfda7866dfb77498c63a7ae9e7d0772fe9ba938a9ff6c0209196988158e6ea055fe967dd7599ef4bd7f306ded231cca10d89b4d6de40916e615d1d4cc6032585822a650743e34735d464fc0d544d1fad8c293df22f4a55ce3fbfb55d90cdc5ab84695a5a13d46f3176f143d9d28f60dca841eac603d30cec830a62feec091c927e6c781df330f14ca10203010001a3818b30818830130603551d25040c300a06082b0601050507030130230603551d11041c301a8218666c6f776572732d746f2d7468652d776f726c642e636f6d300c0603551d130101ff04023000301f0603551d23041830168014e93c04e1802fc284132d26709ef2fd1acfaafec6301d0603551d0e041604142f3948061fe546939f5e8dbc3fe4c0a1fbaab6b7300d06092a864886f70d01010b0500038202010052a2480c754c51cfdc9f99a82a8eb7c34e5e2bdcdfdd7543fadadb578083416d34ebb87fea3c90baf97f06be5baf5c41101ad1bdd2a2f554de6a3e8cd5ff3d78354badad01032a007d2eaf03590ee5397e223b2936f0c8b59c0407079c8975ffb34eb1cfe784cf3bc45e198a601473537f1ef382e0b5311d2ddf430ade7cfd28900ec9d91c1db49a6b2fb1b9e13b94135fed978d646e048b2fa9dc36ef5821cea8ebbed38d4c2d7811e9660f23d7636b295caccdc945a010a4c364fd7e7480aa5282d28fc46ce7f4f636ef2cc57c8bb1aee5da79bc6107205d4abcd3fb09a1db023ba4e8e9f34ae36ff5b2672fc2a14af8d23d67a437b3eb507ca90f73121841ab1498ab712d18063244dc3514bfffbaf6d45acdfc5316a248589a04b79b2abbca454e2e21f9b487e21eea21565c99ebc1013b87253c91f43ac6d2d2dea7090877c2a7404bce2545662ce005dc12eb57b1efe7145af8070b5dfa86736664a644a9c0f7e7c38d715cf874b818d519927eddc69b55c781b6e0a6eef8f3e46b9e059105b7932a978704e924904dbaa9583f3dd606467f4cc41589b702f1a02d517d3cd93b55d67d0b379e2527fded951be9dfb86d473613e6d9b8399ef5174d3e03185bd3cb4ea859b465c6c49010d4119d613a60878c0e453f17cfa3ce925e10f6e0a5adb745cebe218c3c82627a120e2907eeb9ec5307664474093cbc92d65fc7"
leafCA = "308205c8308203b0a00302010202021001300d06092a864886f70d0101050500307d310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793121301f06035504030c184d657267652044656c6179204d6f6e69746f7220526f6f74301e170d3134303731373132323633305a170d3139303731363132323633305a307f310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793123302106035504030c1a4d657267652044656c617920496e7465726d656469617465203130820222300d06092a864886f70d01010105000382020f003082020a0282020100c1e874feff9aeef303bbfa63453881faaf8dc1c22c09641daf430381f33bc157bf6c4c8a8d57b1abc792859d20f2191509c597c437b14673dea5af4bea14396dd436dc620555d7953e0ede01f7ffb44f3ff7cde64ed245634e0df0aafce9c3ac5eb63d8de1d969cac8854195403a9f9d1d4c3dceedf1351edd945743bc54ab745b204fb5259fe3edf695c2cf90b886c48ff680b744fec2691b4345242b31c36f3118b727c5de5c25ec1aa30a4c2461c5119ef6bb90d816e6e44c5b9955bfa2ed3416bf6e4a53c92fafac0d1f0b8bf3d35be0d4f61ca05d28fc662dfa588fba3ee0380470c012ded9e51bbf1e7a25efa745784c49d05eaf8dcee0527361ec913126005e972cf4b863914f8361582ed24563ff9e03c52e8a9ca3264c56c186b4ec52b7e695ce42ae17ec7ae0257131e1dbf48f2dde242e6e91ea304988135a15482b05fc091355328b39e586e8dd3a4a3a14cb97eef68f9f69728c291f2195d2cce73d4ae90845b1bfc5fae040b94fc359a29511981b9966aeb56d3a7c5e48f8eca815e5be86b3d36e6a27e0e2c4dee6e30f12a7c936b8c98cad5928aca238dfc39cf9f2c5246cbbbb280cb6f99eb49bfd1d78089539072c164c7083371746dedbc4dec1cb9439073af3f2e60f8c505f067961a8c539454fc5341158eccc78532f3e39c3187c9439fc0ff88ee957131d478df063dd50b2ad3fe7a070e905e3868b0203010001a350304e301d0603551d0e04160414e93c04e1802fc284132d26709ef2fd1acfaafec6301f0603551d23041830168014f35f7b7549e37841396a20b67c6b4c5cc93d5841300c0603551d13040530030101ff300d06092a864886f70d010105050003820201000858cbd545f2e92e09906ac39f3d55c13607a651436386c6e90f128773a0eb3f4725d8af35fb7f880436b481f2cf47801825de54f13f8f5920bf3d916e753141de5e59d2debbfc3fc226721f15a16d3b7a4618ea0551639f1d2cb7b9faad1b7e070f23a6e8197c3d7549bba6553fd5db419ce399477f6a0481b90f51c9d307d82cb05cf967828a1ace65207cf86b6d16792245dcf24b4c179f91184736e7e2fcb863a4b5c89b0ac2f368390a10594b95c856e259c77564316898cf87a6817d18585fc976d681d9d510ef2ad37e8ad0e49f5bd499c9ec7fe8f43b17dffb9b7d0dfd8300c1c5389c9ea0be4370dcbf78bd3efc2308d250b866bbca031c0c49ff77a7a5420daa1f1b6a444d366653974c2d179c3009871ee6c89140fca9efdf23bd4b88c6ebaeb9286f58f3cfc21e4874f182d1ecd6058919b03b18db7b795be9cb25fc5166a945ef8e1133cd60312a3234f4649df6166407cbb5ecc838e9e118c05dee7c896a9987655ae7e349cd8166e68d34dea3b4ae892a9f2385053271e860b542be3650503974f3bb6f2688375ab28487da6751d0f2c3a35e78efe30b19d57808ebea2c4453990ad81eb96289c0f99c5080f82092bc6123a340c63a617f3bc4adc1298d88a278a693ef93688611d3b4eded0b6d023ed9f6c2ea8836483197525b1b1bce70a90c3403b094d5f412aa1141b9965ab8314c52f772deffc1008c"
rootCA = "308205cd308203b5a0030201020209009ed3ccb1d12ca272300d06092a864886f70d0101050500307d310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793121301f06035504030c184d657267652044656c6179204d6f6e69746f7220526f6f74301e170d3134303731373132303534335a170d3431313230323132303534335a307d310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793121301f06035504030c184d657267652044656c6179204d6f6e69746f7220526f6f7430820222300d06092a864886f70d01010105000382020f003082020a0282020100aa161cf2205ed81ac565483cda426a3db2e588fdb758b17b93ea8d68495d534a01ba4f6cd1c0fc0a128af79c066dc54c3f437e05ba275ee61dbf9cbdb2928183738139397b6189ae738fef2b9b609a6dd8e0b0d0e20b243db936c029cdc2220af2c0e1a5e4aa41a006af458957e2b1178d27156ef0cb717e16d54025d97f43e9916fb240fb85f7d579462fa0ac76c76256843750bf1ccdfeb76c8c47886477644d5ec3235628adf6a09c8488bfa5036de717908151a6b585f273dd9fb5332b9af76e8fbfa91eaf4311816dde27c5c44f2fd06cc2204d7147f77ba6b16a2a5fca470023614729538bee6b3cb07264713832aec161550eb501906802215223acc2564ad1f98bb5934924eb56d383fc7598be45c89d995281c0efb0d206d29a6d25a10a48fe235332379c5ca69e83599faa677dd20823f5c84a961255eca5d4871d54ca1df0774aa117b0f42cd6e9fda7e8a48a53923c5f94043353544e644b5a6562e5cef9fc2bd2fcfcce3323335cf7fe7c4d83c1b7f839c4790192d3ba9aa9f32093aa8ee7cbe708059d538dc663cca1b825331aa836754a0d13de63bf65b6e2044dcdf041f1a0c5a9c3c38fe74cf576d451c23eaa519db32ef9e039bd848a194c3b5e41a55642dc283ddbd73d1dd97ae6951de18ad89d005007fae7e88bc7a3cce8b7ccc49603a0db67c76d58a28d4b77aa7460801e34377d0c5e4606c2e25b0203010001a350304e301d0603551d0e04160414f35f7b7549e37841396a20b67c6b4c5cc93d5841301f0603551d23041830168014f35f7b7549e37841396a20b67c6b4c5cc93d5841300c0603551d13040530030101ff300d06092a864886f70d01010505000382020100771cfea34579a97520d8c2423d68ecd07891f8c7f1c38bf3cd30ea9d3637bfc5d373532ec7656558bef4950646750c6fe085c52d9ffc09e66ebfa2b067de7727cb381d2b25db58b9c2197fd5eb53e020f429b86a3b1f37a07a761a66a5b3ecd797c46695a37ff2d47c54126be6bd28a2a103357227c6b73f7f689b09b48927e6e9a52267a728a115d4bcbb477533dc28f3fc57da735a3ec54fbc36990b17febb7e46b324208c1fa7425a0cba48bdc0381ea8285215261c3c483f2fa6d1da0dba4949107189f32d728a7ff395d43430af3b8ce4be5075bcf67d66661941dc8be37340f8f9282b2d2aadd69065932ad49769f8bc7fc9e5f6e79ff392420ba78de3172778e2b67e4df18440dd561e5a7844c8efa06c0e5f5b8695fa069114a00518fb4c19f9d7855831b5eeebced14b8598daffa49f2dcf505bff6417d84b28e83599d4e0371ef64b2d82ffa068a31044f7322fee2f654ec357c9c121f3458a509728c37f5673412ad0d5e76aa6b4eb1582181a8be404d3dc35e71edd83ee388087d6147c4d86f1cacacface0104df1f4b100c2ceb1be4d1851c4f31e7c4409262185878f23cceb30790143f0d5bd80d2c0ed4260aaa312597d950aaf3c8bcfc812d9a56e8d160dd772a494743710a7e478a046d8a5d505ee6b8cc37fec09dfd4cb57c6c4d8e8ef2a22e1d9e50957852633138d722253e51ba77b0069d38812207a"
noExts = "0000"
// Precert example taken from entry #2 in argon2018 log
issuerKeyHash = "e37689003073a0c649cc656de946c03174d25c566fe3c3805b846f5236943798"
precertTBS = "0002db308202d7a0030201020207055667377e8bcc300d06092a864886f70d01010b0500307f310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793123302106035504030c1a4d657267652044656c617920496e7465726d6564696174652031301e170d3137303831303134343331365a170d3138303432363134323430315a3063310b3009060355040613024742310f300d06035504070c064c6f6e646f6e31283026060355040a0c1f476f6f676c65204365727469666963617465205472616e73706172656e637931193017060355040513103135303233373631393632313337303830820122300d06092a864886f70d01010105000382010f003082010a0282010100dea100ff02f31ae6f76f9c26525afcdd0ef6eef780d72b4b1c0ff14fc7ac021852d6f34af20713d05fea2c2e1a4b488b3849c2511cf30fcd2e61d9e7392557498a4ff600c8fdc912f05c8a583a5f2b6a3d3320c6cc10b7eed502de392d11b3c4d57fa6e3ddc69d3f73305bb6441a0359bd526272784523ae5319cffd2993abba54d26c4c1b760c8660b65161a349e415207a6fbb20d02ce13054e6ffa7776bccfd26c3e4220e0e504f102f352260aaa9864411f7eeae8f6071c9ba54b83d11af43ab58dcb6a7d9053654b98b165fb84a27c78361d957c70a064f45bf4501ef744302e497839a34222e94b3018e587c70c130208976d9f80cf6741a95abfa6b810203010001a3818b30818830130603551d25040c300a06082b0601050507030130230603551d11041c301a8218666c6f776572732d746f2d7468652d776f726c642e636f6d300c0603551d130101ff04023000301f0603551d23041830168014e93c04e1802fc284132d26709ef2fd1acfaafec6301d0603551d0e04160414df25c220250d548e08341c26cadc5effc177841c"
precertDER = "30820504308202eca0030201020207055667377e8bcc300d06092a864886f70d01010b0500307f310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793123302106035504030c1a4d657267652044656c617920496e7465726d6564696174652031301e170d3137303831303134343331365a170d3138303432363134323430315a3063310b3009060355040613024742310f300d06035504070c064c6f6e646f6e31283026060355040a0c1f476f6f676c65204365727469666963617465205472616e73706172656e637931193017060355040513103135303233373631393632313337303830820122300d06092a864886f70d01010105000382010f003082010a0282010100dea100ff02f31ae6f76f9c26525afcdd0ef6eef780d72b4b1c0ff14fc7ac021852d6f34af20713d05fea2c2e1a4b488b3849c2511cf30fcd2e61d9e7392557498a4ff600c8fdc912f05c8a583a5f2b6a3d3320c6cc10b7eed502de392d11b3c4d57fa6e3ddc69d3f73305bb6441a0359bd526272784523ae5319cffd2993abba54d26c4c1b760c8660b65161a349e415207a6fbb20d02ce13054e6ffa7776bccfd26c3e4220e0e504f102f352260aaa9864411f7eeae8f6071c9ba54b83d11af43ab58dcb6a7d9053654b98b165fb84a27c78361d957c70a064f45bf4501ef744302e497839a34222e94b3018e587c70c130208976d9f80cf6741a95abfa6b810203010001a381a030819d30130603551d25040c300a06082b0601050507030130230603551d11041c301a8218666c6f776572732d746f2d7468652d776f726c642e636f6d300c0603551d130101ff04023000301f0603551d23041830168014e93c04e1802fc284132d26709ef2fd1acfaafec6301d0603551d0e04160414df25c220250d548e08341c26cadc5effc177841c3013060a2b06010401d6790204030101ff04020500300d06092a864886f70d01010b05000382020100ae9ca16ec19bb469d08628b1296f50e3e15b362e2b18c691b11eef3af9ce655bf74e0c21c84f6091132851ba78465c3ae97a1409ee7505395d4e7e0318189029a12bf1c3ba2b6f3231c7aac13dbbfaade8d56f0fbe91d32440ad0ab816184c72392154275ead8418cc62e4e2b08de1b14acb6b27c0f36fa586feb875666f46d232a32ef022440d52cdd8bd31a42de55bfa77de8742816f086830b07eedbde545af5a2b9dd17bd49ded508589a0673f6e0d55f210818422093fd10939f0c81521ca654958e6e01b76ef8c7380bdb331e67d44ccb18a83ed04d97d463c37c7cbc592768e2373e198a1d64be3bd22d1833994706797461d05a85e779cd6e2b4b2b14e81d1eca454f29780c47a7366041ace1a48319eff3f1f04bbd471d5125774ef050e47bf664a98101b7be3337bb786b760a92be46488c6a15f72972a4b7c932c736311f0ac1d40920580329657f00e26cfb6d3b1db1eb7a95952fbcbfcbaf9d17587f03aeb9c3b403d1dccad895316658d35fe385fc5a62b60db36e3f07c4798314936aeb3f40094aee9ec1350ea8f68d1aeb41b211ecd0c9e29c5fa2d6576bcb2ad5ec8cc936e1f5a127afa0de3ae490b914adaa733f18ed9348d497e10ba4aa3008f84deec6976292dc0d3c2aa523602188916dd468b47f3d571e71fe51cd293c805d1280a53ab9f519a616d889303be461354edfc29dc3cc85d8570264cf4"
precertCA = "308205c8308203b0a00302010202021001300d06092a864886f70d0101050500307d310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793121301f06035504030c184d657267652044656c6179204d6f6e69746f7220526f6f74301e170d3134303731373132323633305a170d3139303731363132323633305a307f310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793123302106035504030c1a4d657267652044656c617920496e7465726d656469617465203130820222300d06092a864886f70d01010105000382020f003082020a0282020100c1e874feff9aeef303bbfa63453881faaf8dc1c22c09641daf430381f33bc157bf6c4c8a8d57b1abc792859d20f2191509c597c437b14673dea5af4bea14396dd436dc620555d7953e0ede01f7ffb44f3ff7cde64ed245634e0df0aafce9c3ac5eb63d8de1d969cac8854195403a9f9d1d4c3dceedf1351edd945743bc54ab745b204fb5259fe3edf695c2cf90b886c48ff680b744fec2691b4345242b31c36f3118b727c5de5c25ec1aa30a4c2461c5119ef6bb90d816e6e44c5b9955bfa2ed3416bf6e4a53c92fafac0d1f0b8bf3d35be0d4f61ca05d28fc662dfa588fba3ee0380470c012ded9e51bbf1e7a25efa745784c49d05eaf8dcee0527361ec913126005e972cf4b863914f8361582ed24563ff9e03c52e8a9ca3264c56c186b4ec52b7e695ce42ae17ec7ae0257131e1dbf48f2dde242e6e91ea304988135a15482b05fc091355328b39e586e8dd3a4a3a14cb97eef68f9f69728c291f2195d2cce73d4ae90845b1bfc5fae040b94fc359a29511981b9966aeb56d3a7c5e48f8eca815e5be86b3d36e6a27e0e2c4dee6e30f12a7c936b8c98cad5928aca238dfc39cf9f2c5246cbbbb280cb6f99eb49bfd1d78089539072c164c7083371746dedbc4dec1cb9439073af3f2e60f8c505f067961a8c539454fc5341158eccc78532f3e39c3187c9439fc0ff88ee957131d478df063dd50b2ad3fe7a070e905e3868b0203010001a350304e301d0603551d0e04160414e93c04e1802fc284132d26709ef2fd1acfaafec6301f0603551d23041830168014f35f7b7549e37841396a20b67c6b4c5cc93d5841300c0603551d13040530030101ff300d06092a864886f70d010105050003820201000858cbd545f2e92e09906ac39f3d55c13607a651436386c6e90f128773a0eb3f4725d8af35fb7f880436b481f2cf47801825de54f13f8f5920bf3d916e753141de5e59d2debbfc3fc226721f15a16d3b7a4618ea0551639f1d2cb7b9faad1b7e070f23a6e8197c3d7549bba6553fd5db419ce399477f6a0481b90f51c9d307d82cb05cf967828a1ace65207cf86b6d16792245dcf24b4c179f91184736e7e2fcb863a4b5c89b0ac2f368390a10594b95c856e259c77564316898cf87a6817d18585fc976d681d9d510ef2ad37e8ad0e49f5bd499c9ec7fe8f43b17dffb9b7d0dfd8300c1c5389c9ea0be4370dcbf78bd3efc2308d250b866bbca031c0c49ff77a7a5420daa1f1b6a444d366653974c2d179c3009871ee6c89140fca9efdf23bd4b88c6ebaeb9286f58f3cfc21e4874f182d1ecd6058919b03b18db7b795be9cb25fc5166a945ef8e1133cd60312a3234f4649df6166407cbb5ecc838e9e118c05dee7c896a9987655ae7e349cd8166e68d34dea3b4ae892a9f2385053271e860b542be3650503974f3bb6f2688375ab28487da6751d0f2c3a35e78efe30b19d57808ebea2c4453990ad81eb96289c0f99c5080f82092bc6123a340c63a617f3bc4adc1298d88a278a693ef93688611d3b4eded0b6d023ed9f6c2ea8836483197525b1b1bce70a90c3403b094d5f412aa1141b9965ab8314c52f772deffc1008c"
precertRoot = "308205cd308203b5a0030201020209009ed3ccb1d12ca272300d06092a864886f70d0101050500307d310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793121301f06035504030c184d657267652044656c6179204d6f6e69746f7220526f6f74301e170d3134303731373132303534335a170d3431313230323132303534335a307d310b3009060355040613024742310f300d06035504080c064c6f6e646f6e31173015060355040a0c0e476f6f676c6520554b204c74642e3121301f060355040b0c184365727469666963617465205472616e73706172656e63793121301f06035504030c184d657267652044656c6179204d6f6e69746f7220526f6f7430820222300d06092a864886f70d01010105000382020f003082020a0282020100aa161cf2205ed81ac565483cda426a3db2e588fdb758b17b93ea8d68495d534a01ba4f6cd1c0fc0a128af79c066dc54c3f437e05ba275ee61dbf9cbdb2928183738139397b6189ae738fef2b9b609a6dd8e0b0d0e20b243db936c029cdc2220af2c0e1a5e4aa41a006af458957e2b1178d27156ef0cb717e16d54025d97f43e9916fb240fb85f7d579462fa0ac76c76256843750bf1ccdfeb76c8c47886477644d5ec3235628adf6a09c8488bfa5036de717908151a6b585f273dd9fb5332b9af76e8fbfa91eaf4311816dde27c5c44f2fd06cc2204d7147f77ba6b16a2a5fca470023614729538bee6b3cb07264713832aec161550eb501906802215223acc2564ad1f98bb5934924eb56d383fc7598be45c89d995281c0efb0d206d29a6d25a10a48fe235332379c5ca69e83599faa677dd20823f5c84a961255eca5d4871d54ca1df0774aa117b0f42cd6e9fda7e8a48a53923c5f94043353544e644b5a6562e5cef9fc2bd2fcfcce3323335cf7fe7c4d83c1b7f839c4790192d3ba9aa9f32093aa8ee7cbe708059d538dc663cca1b825331aa836754a0d13de63bf65b6e2044dcdf041f1a0c5a9c3c38fe74cf576d451c23eaa519db32ef9e039bd848a194c3b5e41a55642dc283ddbd73d1dd97ae6951de18ad89d005007fae7e88bc7a3cce8b7ccc49603a0db67c76d58a28d4b77aa7460801e34377d0c5e4606c2e25b0203010001a350304e301d0603551d0e04160414f35f7b7549e37841396a20b67c6b4c5cc93d5841301f0603551d23041830168014f35f7b7549e37841396a20b67c6b4c5cc93d5841300c0603551d13040530030101ff300d06092a864886f70d01010505000382020100771cfea34579a97520d8c2423d68ecd07891f8c7f1c38bf3cd30ea9d3637bfc5d373532ec7656558bef4950646750c6fe085c52d9ffc09e66ebfa2b067de7727cb381d2b25db58b9c2197fd5eb53e020f429b86a3b1f37a07a761a66a5b3ecd797c46695a37ff2d47c54126be6bd28a2a103357227c6b73f7f689b09b48927e6e9a52267a728a115d4bcbb477533dc28f3fc57da735a3ec54fbc36990b17febb7e46b324208c1fa7425a0cba48bdc0381ea8285215261c3c483f2fa6d1da0dba4949107189f32d728a7ff395d43430af3b8ce4be5075bcf67d66661941dc8be37340f8f9282b2d2aadd69065932ad49769f8bc7fc9e5f6e79ff392420ba78de3172778e2b67e4df18440dd561e5a7844c8efa06c0e5f5b8695fa069114a00518fb4c19f9d7855831b5eeebced14b8598daffa49f2dcf505bff6417d84b28e83599d4e0371ef64b2d82ffa068a31044f7322fee2f654ec357c9c121f3458a509728c37f5673412ad0d5e76aa6b4eb1582181a8be404d3dc35e71edd83ee388087d6147c4d86f1cacacface0104df1f4b100c2ceb1be4d1851c4f31e7c4409262185878f23cceb30790143f0d5bd80d2c0ed4260aaa312597d950aaf3c8bcfc812d9a56e8d160dd772a494743710a7e478a046d8a5d505ee6b8cc37fec09dfd4cb57c6c4d8e8ef2a22e1d9e50957852633138d722253e51ba77b0069d38812207a"
)
var tests = []struct {
leaf LeafEntry
wantCert bool
wantPrecert bool
wantErr string
}{
{
leaf: LeafEntry{},
wantErr: "failed to unmarshal",
},
{
leaf: LeafEntry{
// {version + leaf_type + timestamp + entry_type + len + cert + exts}
LeafInput: dh("00" + "00" + "0000015dcc2b99c8" + "0000" + "0004f3" + leafDER + noExts),
ExtraData: dh("000ba3" + "0005cc" + leafCA + "0005d1" + rootCA),
},
wantCert: true,
},
{
leaf: LeafEntry{
LeafInput: dh("00" + "00" + "0000015dcc2b99c8" + "0000" + "0004f3" + leafDER + noExts + "ff"),
ExtraData: dh("000ba3" + "0005cc" + leafCA + "0005d1" + rootCA),
},
wantErr: "trailing data",
},
{
leaf: LeafEntry{
LeafInput: dh("00" + "00" + "0000015dcc2b99c8" + "0000" + "0004f3" + leafDER + noExts),
ExtraData: dh("000ba3" + "0005cc" + leafCA + "0005d1" + rootCA + "00"),
},
wantErr: "trailing data",
},
{
leaf: LeafEntry{
LeafInput: dh("00" + "00" + "0000015dcc2b99c8" + "0000" + "0004f3" + leafDER + noExts),
},
wantErr: "failed to unmarshal",
},
{
leaf: LeafEntry{
LeafInput: dh("00" + "00" + "0000015dcc2b99c8" + "8000" + "0004f3" + leafDER + noExts),
},
wantErr: "unknown entry type",
},
{
leaf: LeafEntry{
// version + leaf_type + timestamp + entry_type + key_hash + tbs + exts
LeafInput: dh("00" + "00" + "0000015dcc997890" + "0001" + issuerKeyHash + precertTBS + noExts),
ExtraData: dh("000508" + precertDER +
("000ba3" + "0005cc" + precertCA + "0005d1" + precertRoot)),
},
wantPrecert: true,
},
{
leaf: LeafEntry{
LeafInput: dh("00" + "00" + "0000015dcc997890" + "0001" + issuerKeyHash + precertTBS + noExts),
ExtraData: dh("000508" + precertDER +
("000ba3" + "0005cc" + precertCA + "0005d1" + precertRoot) + "ff"),
},
wantErr: "trailing data",
},
{
leaf: LeafEntry{
LeafInput: dh("00" + "00" + "0000015dcc997890" + "0001" + issuerKeyHash + precertTBS + noExts + "ff"),
ExtraData: dh("000508" + precertDER +
("000ba3" + "0005cc" + precertCA + "0005d1" + precertRoot)),
},
wantErr: "trailing data",
},
{
leaf: LeafEntry{
LeafInput: dh("00" + "00" + "0000015dcc997890" + "0001" + issuerKeyHash + precertTBS + noExts),
},
wantErr: "failed to unmarshal",
},
}
for i, test := range tests {
got, err := LogEntryFromLeaf(int64(i), &test.leaf)
if err != nil {
if test.wantErr == "" {
t.Errorf("LogEntryFromLeaf(%d) = _, %v; want _, nil", i, err)
} else if !strings.Contains(err.Error(), test.wantErr) {
t.Errorf("LogEntryFromLeaf(%d) = _, %v; want _, err containing %q", i, err, test.wantErr)
}
} else if test.wantErr != "" {
t.Errorf("LogEntryFromLeaf(%d) = _, nil; want _, err containing %q", i, test.wantErr)
}
if gotCert := (got != nil && got.X509Cert != nil); gotCert != test.wantCert {
t.Errorf("LogEntryFromLeaf(%d).X509Cert = %v; want %v", i, gotCert, test.wantCert)
}
if gotPrecert := (got != nil && got.Precert != nil); gotPrecert != test.wantPrecert {
t.Errorf("LogEntryFromLeaf(%d).Precert = %v; want %v", i, gotPrecert, test.wantPrecert)
}
}
}

View File

@ -1,493 +0,0 @@
// Copyright 2015 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 ct
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"encoding/hex"
mrand "math/rand"
"testing"
"github.com/google/certificate-transparency-go/tls"
)
const (
sigTestDERCertString = "308202ca30820233a003020102020102300d06092a864886f70d01010505003055310b300" +
"906035504061302474231243022060355040a131b4365727469666963617465205472616e" +
"73706172656e6379204341310e300c0603550408130557616c65733110300e06035504071" +
"3074572772057656e301e170d3132303630313030303030305a170d323230363031303030" +
"3030305a3052310b30090603550406130247423121301f060355040a13184365727469666" +
"963617465205472616e73706172656e6379310e300c0603550408130557616c6573311030" +
"0e060355040713074572772057656e30819f300d06092a864886f70d010101050003818d0" +
"030818902818100b8742267898b99ba6bfd6e6f7ada8e54337f58feb7227c46248437ba5f" +
"89b007cbe1ecb4545b38ed23fddbf6b9742cafb638157f68184776a1b38ab39318ddd7344" +
"89b4d750117cd83a220a7b52f295d1e18571469a581c23c68c57d973761d9787a091fb586" +
"4936b166535e21b427e3c6d690b2e91a87f36b7ec26f59ce53b50203010001a381ac3081a" +
"9301d0603551d0e041604141184e1187c87956dffc31dd0521ff564efbeae8d307d060355" +
"1d23047630748014a3b8d89ba2690dfb48bbbf87c1039ddce56256c6a159a4573055310b3" +
"00906035504061302474231243022060355040a131b436572746966696361746520547261" +
"6e73706172656e6379204341310e300c0603550408130557616c65733110300e060355040" +
"713074572772057656e82010030090603551d1304023000300d06092a864886f70d010105" +
"050003818100292ecf6e46c7a0bcd69051739277710385363341c0a9049637279707ae23c" +
"c5128a4bdea0d480ed0206b39e3a77a2b0c49b0271f4140ab75c1de57aba498e09459b479" +
"cf92a4d5d5dd5cbe3f0a11e25f04078df88fc388b61b867a8de46216c0e17c31fc7d8003e" +
"cc37be22292f84242ab87fb08bd4dfa3c1b9ce4d3ee6667da"
sigTestSCTTimestamp = 1348589665525
sigTestCertSCTSignatureEC = "0403" + "0048" +
"3046022100d3f7690e7ee80d9988a54a3821056393e9eb0c686ad67fbae3686c888fb1a3c" +
"e022100f9a51c6065bbba7ad7116a31bea1c31dbed6a921e1df02e4b403757fae3254ae"
sigTestEC256PrivateKeyPEM = "-----BEGIN EC PRIVATE KEY-----\n" +
"MHcCAQEEIG8QAquNnarN6Ik2cMIZtPBugh9wNRe0e309MCmDfBGuoAoGCCqGSM49\n" +
"AwEHoUQDQgAES0AfBkjr7b8b19p5Gk8plSAN16wWXZyhYsH6FMCEUK60t7pem/ck\n" +
"oPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n" +
"-----END EC PRIVATE KEY-----\n"
sigTestEC256PublicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" +
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAES0AfBkjr7b8b19p5Gk8plSAN16wW\n" +
"XZyhYsH6FMCEUK60t7pem/ckoPX8hupuaiJzJS0ZQ0SEoJGlFxkUFwft5g==\n" +
"-----END PUBLIC KEY-----\n"
sigTestEC256PublicKey2PEM = "-----BEGIN PUBLIC KEY-----\n" +
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHT\n" +
"DM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==\n" +
"-----END PUBLIC KEY-----\n"
sigTestRSAPrivateKeyPEM = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MIIEpAIBAAKCAQEAxy7llbig9kL0wo5AyV1FhmJLvWTWxzAMwGdhG1h1CqQpaWut\n" +
"XGI9WKRDJSZ/9dr9vgvqdRX2QsnUdJbJ3cz5Z1ie/RdT/mSVO7ZEqvJS93PIHnqu\n" +
"FZXxNnIerGnQ7guC+Zm9BlQ2DIhYpnvVRRVyD/D8KT92R7qOu3JACduoMrF1synk\n" +
"nL8rb8lZvCej8tbhJ38yibMWTmkxsFS+a29Xqk8pkhgwIwvUZqcMaqZo+4/iCuKL\n" +
"bVc85V98SvbcnmsX3gqeQnyRtxlctlclcbvHmJt5U+3yF1UtcuiyZf1gjcAqnOgv\n" +
"ZZYzsodXi0KGV7NRQhTPvwH0C8In2qL+v4qWAQIDAQABAoIBAQCdyqsaNw9cx6I6\n" +
"1pLAcuF3GjvCKDZ1ybzwV3V4QlVGPtKHr0PBIhpTNJ30ulE4pWnKuoncg695LYbf\n" +
"be0xhwY1NuGMwoRJzcjjavtvKVVMry5j5vAuLYDPjwx5rcJUMk5qCb7TWrcOqp0A\n" +
"Fq3XcqvPsSsyShIbtNEJ8fKFXLwcm07bGDgOacrXieP/nL2Hh6joeAJLgnKAOtU5\n" +
"qw6fdweYGThfhdCwaBq0WSaxj6nMG3Q40bHurvdOAtU1GF2a27BGsnfKFyKlvk8+\n" +
"K7tCc4oXo4WWEUuOwu6SmB1kYIZLf258B0PFQJwN8OA3Mbek+F4Bm3DzWe1aLS5L\n" +
"wpOYxrq5AoGBAO0sGq+ic+9K81FvBBUYXiFtt9rv3nU9jZhjqpfvdqRs2KXt8ldz\n" +
"2M+JCRFHt8rLDEutK/NZuZcq3wAXS3EeMIp33QZ7Yuj5LeG9eD0asX8yq51Toua3\n" +
"gRDbiR00Vz/3BINM8JufN/sPLoUiuAV5mlOTktZ8+z7ixO4ravMB1Z9HAoGBANb+\n" +
"w+1Hre8+4JEnl3yRh1UNDmbhCc2tRxCD4QJyb9qaOl2IK1QXuDcwD8owdenwOrAi\n" +
"I5yKx7y4oKNfdSrP2wlAGS/GAEL5f+JhLtv2cNoKNxMXNRgYfJAQeMKBjINdECia\n" +
"G89lbPVCm+F3guzrO70giA4617GFSEA31rRC1BR3AoGBAKcQLiwRrsCcdxChtqp1\n" +
"Y7kAZEXgOT80gI0bh4tGrrfbxC/9kHtxqwNlb/GwJxK+PIcCELd2OHj3ReX2grnH\n" +
"nkGrdRGf0GhzPZKJuCyypN0IgEJuK42BLXUGb2sW926jPZaPl9zHJtO+OfKmJiIV\n" +
"KlQ8224i04fUjQuHoepTHHr5AoGAS8AZ4lmWFCywTRSJEG/qIfJmt6LkpF5AIraE\n" +
"qisN9BTRKbFXqtpsoq1BcvjeIt3sn7B3oalYNMtMdiOlEb+Iqlq2RRnbb72e7HFX\n" +
"ZFMRchGVVBmiMGo4QT48fjPNAV/h2Jxr3ggbetLMP4WvULCVLM7wgSsEYlzWlyHV\n" +
"eU/uj4MCgYADGpY3Q3ueB23eTTnAMtESwmAQvjTBOPKVpaV/ohHb8BdzAjwcgEUA\n" +
"wB1be/bHCrLbW09Pi3HVp0I0x0mBAYoUP2NRYKCYlhs28cu+ygB4nsy+YZPg00+E\n" +
"ByqqrQ0zuN82ytXzRFHmh2Hb2O+HOj6aJjgVuj/rR7aifIt8scSAhg==\n" +
"-----END RSA PRIVATE KEY-----\n"
sigTestRSAPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxy7llbig9kL0wo5AyV1F\n" +
"hmJLvWTWxzAMwGdhG1h1CqQpaWutXGI9WKRDJSZ/9dr9vgvqdRX2QsnUdJbJ3cz5\n" +
"Z1ie/RdT/mSVO7ZEqvJS93PIHnquFZXxNnIerGnQ7guC+Zm9BlQ2DIhYpnvVRRVy\n" +
"D/D8KT92R7qOu3JACduoMrF1synknL8rb8lZvCej8tbhJ38yibMWTmkxsFS+a29X\n" +
"qk8pkhgwIwvUZqcMaqZo+4/iCuKLbVc85V98SvbcnmsX3gqeQnyRtxlctlclcbvH\n" +
"mJt5U+3yF1UtcuiyZf1gjcAqnOgvZZYzsodXi0KGV7NRQhTPvwH0C8In2qL+v4qW\n" +
"AQIDAQAB\n" +
"-----END PUBLIC KEY-----\n"
sigTestCertSCTSignatureRSA = "0401" + "0100" +
"6bc1fecfe9052036e31278cd7eded90d000b127f2b657831baf5ecb31ee3" +
"c17497abd9562df6319928a36df0ab1a1a917b3f4530e1ca0000ae6c4a0c" +
"0efada7df83beb95da8eea98f1a27c70afa1ccaa7a0245e1db785b1c0d9f" +
"ee307e926e14bed1eac0d01c34939e659360432a9552c02b89c3ef3c44aa" +
"22fc31f2444522975ee83989dd7af1ab05b91bbf0985ca4d04245b68a683" +
"01d300f0c976ce13d58618dad1b49c0ec5cdc4352016823fc88c479ef214" +
"76c5f19923af207dbb1b2cff72d4e1e5ee77dd420b85d0f9dcc30a0f617c" +
"2d3c916eb77f167323500d1b53dc4253321a106e441af343cf2f68630873" +
"abd43ca52629c586107eb7eb85f2c3ee"
sigTestCertSCTSignatureUnsupportedSignatureAlgorithm = "0402" + "0000"
sigTestCertSCTSignatureUnsupportedHashAlgorithm = "0303" + "0000"
// Some time in September 2012.
sigTestDefaultSTHTimestamp = 1348589667204
sigTestDefaultTreeSize = 42
// *Some* hash that we pretend is a valid root hash.
sigTestDefaultRootHash = "18041bd4665083001fba8c5411d2d748e8abbfdcdfd9218cb02b68a78e7d4c23"
sigTestDefaultSTHSerialized = "000100000139fe354384000000000000002a18041bd4665083001fba8c5411d2d748e8abb" +
"fdcdfd9218cb02b68a78e7d4c23"
sigTestDefaultSTHSignature = "0403" + "0048" +
"3046022100befd8060563763a5e49ba53e6443c13f7624fd6403178113736e16012aca983" +
"e022100f572568dbfe9a86490eb915c4ee16ad5ecd708fed35ed4e5cd1b2c3f087b4130"
sigTestKeyIDEC = "b69d879e3f2c4402556dcda2f6b2e02ff6b6df4789c53000e14f4b125ae847aa"
sigTestKeyIDRSA = "b853f84c71a7aa5f23905ba5340f183af927c330c7ce590ba1524981c4ec4358"
)
func mustDehex(t *testing.T, h string) []byte {
t.Helper()
r, err := hex.DecodeString(h)
if err != nil {
t.Fatalf("Failed to decode hex string (%s): %v", h, err)
}
return r
}
func sigTestSCTWithSignature(t *testing.T, sig, keyID string) SignedCertificateTimestamp {
t.Helper()
var ds DigitallySigned
if _, err := tls.Unmarshal(mustDehex(t, sig), &ds); err != nil {
t.Fatalf("Failed to unmarshal sigTestCertSCTSignatureEC: %v", err)
}
var id LogID
copy(id.KeyID[:], mustDehex(t, keyID))
return SignedCertificateTimestamp{
SCTVersion: V1,
LogID: id,
Timestamp: sigTestSCTTimestamp,
Signature: ds,
}
}
func sigTestSCTEC(t *testing.T) SignedCertificateTimestamp {
t.Helper()
return sigTestSCTWithSignature(t, sigTestCertSCTSignatureEC, sigTestKeyIDEC)
}
func sigTestSCTRSA(t *testing.T) SignedCertificateTimestamp {
t.Helper()
return sigTestSCTWithSignature(t, sigTestCertSCTSignatureRSA, sigTestKeyIDEC)
}
func sigTestECPublicKey(t *testing.T) crypto.PublicKey {
t.Helper()
pk, _, _, err := PublicKeyFromPEM([]byte(sigTestEC256PublicKeyPEM))
if err != nil {
t.Fatalf("Failed to parse sigTestEC256PublicKey: %v", err)
}
return pk
}
func sigTestECPublicKey2(t *testing.T) crypto.PublicKey {
t.Helper()
pk, _, _, err := PublicKeyFromPEM([]byte(sigTestEC256PublicKey2PEM))
if err != nil {
t.Fatalf("Failed to parse sigTestEC256PublicKey2: %v", err)
}
return pk
}
func sigTestRSAPublicKey(t *testing.T) crypto.PublicKey {
t.Helper()
pk, _, _, err := PublicKeyFromPEM([]byte(sigTestRSAPublicKeyPEM))
if err != nil {
t.Fatalf("Failed to parse sigTestRSAPublicKey: %v", err)
}
return pk
}
func sigTestCertLogEntry(t *testing.T) LogEntry {
t.Helper()
return LogEntry{
Index: 0,
Leaf: MerkleTreeLeaf{
Version: V1,
LeafType: TimestampedEntryLeafType,
TimestampedEntry: &TimestampedEntry{
Timestamp: sigTestSCTTimestamp,
EntryType: X509LogEntryType,
X509Entry: &ASN1Cert{Data: mustDehex(t, sigTestDERCertString)},
},
},
}
}
func sigTestDefaultSTH(t *testing.T) SignedTreeHead {
t.Helper()
var ds DigitallySigned
if _, err := tls.Unmarshal(mustDehex(t, sigTestDefaultSTHSignature), &ds); err != nil {
t.Fatalf("Failed to unmarshal sigTestCertSCTSignatureEC: %v", err)
}
var rootHash SHA256Hash
copy(rootHash[:], mustDehex(t, sigTestDefaultRootHash))
return SignedTreeHead{
Version: V1,
Timestamp: sigTestDefaultSTHTimestamp,
TreeSize: sigTestDefaultTreeSize,
SHA256RootHash: rootHash,
TreeHeadSignature: ds,
}
}
func mustCreateSignatureVerifier(t *testing.T, pk crypto.PublicKey) SignatureVerifier {
t.Helper()
sv, err := NewSignatureVerifier(pk)
if err != nil {
t.Fatalf("Failed to create SignatureVerifier: %v", err)
}
return *sv
}
func corruptByteAt(b []byte, pos int) {
b[pos] ^= byte(mrand.Intn(255) + 1)
}
func corruptBytes(b []byte) {
corruptByteAt(b, mrand.Intn(len(b)))
}
func expectVerifySCTToFail(t *testing.T, sv SignatureVerifier, sct SignedCertificateTimestamp, msg string) {
t.Helper()
if err := sv.VerifySCTSignature(sct, sigTestCertLogEntry(t)); err == nil {
t.Fatal(msg)
}
}
func TestVerifySCTSignatureEC(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
if err := v.VerifySCTSignature(sigTestSCTEC(t), sigTestCertLogEntry(t)); err != nil {
t.Fatalf("Failed to verify signature on SCT: %v", err)
}
}
func TestVerifySCTSignatureRSA(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestRSAPublicKey(t))
if err := v.VerifySCTSignature(sigTestSCTRSA(t), sigTestCertLogEntry(t)); err != nil {
t.Fatalf("Failed to verify signature on SCT: %v", err)
}
}
func TestVerifySCTSignatureFailsForMismatchedSignatureAlgorithm(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
expectVerifySCTToFail(t, v, sigTestSCTRSA(t), "Successfully verified with mismatched signature algorithm")
}
func TestVerifySCTSignatureFailsForUnknownSignatureAlgorithm(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
expectVerifySCTToFail(t, v, sigTestSCTWithSignature(t, sigTestCertSCTSignatureUnsupportedSignatureAlgorithm, sigTestKeyIDEC),
"Successfully verified signature with unsupported signature algorithm")
}
func TestVerifySCTSignatureFailsForUnknownHashAlgorithm(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
expectVerifySCTToFail(t, v, sigTestSCTWithSignature(t, sigTestCertSCTSignatureUnsupportedHashAlgorithm, sigTestKeyIDEC),
"Successfully verified signature with unsupported hash algorithm")
}
func testVerifySCTSignatureFailsForIncorrectLeafBytes(t *testing.T, sct SignedCertificateTimestamp, sv SignatureVerifier) {
t.Helper()
entry := sigTestCertLogEntry(t)
for i := range entry.Leaf.TimestampedEntry.X509Entry.Data {
old := entry.Leaf.TimestampedEntry.X509Entry.Data[i]
corruptByteAt(entry.Leaf.TimestampedEntry.X509Entry.Data, i)
if err := sv.VerifySCTSignature(sct, entry); err == nil {
t.Fatalf("Incorrectly verfied signature over corrupted leaf data, uncovered byte at %d?", i)
}
entry.Leaf.TimestampedEntry.X509Entry.Data[i] = old
}
// Ensure we were only corrupting one byte at a time, should be correct again now.
if err := sv.VerifySCTSignature(sct, entry); err != nil {
t.Fatalf("Input data appears to still be corrupt, bug? %v", err)
}
}
func testVerifySCTSignatureFailsForIncorrectSignature(t *testing.T, sct SignedCertificateTimestamp, sv SignatureVerifier) {
t.Helper()
corruptBytes(sct.Signature.Signature)
expectVerifySCTToFail(t, sv, sct, "Incorrectly verified corrupt signature")
}
func TestVerifySCTSignatureECFailsForIncorrectLeafBytes(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
testVerifySCTSignatureFailsForIncorrectLeafBytes(t, sigTestSCTEC(t), v)
}
func TestVerifySCTSignatureECFailsForIncorrectTimestamp(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sct := sigTestSCTEC(t)
sct.Timestamp++
expectVerifySCTToFail(t, v, sct, "Incorrectly verified signature with incorrect SCT timestamp.")
}
func TestVerifySCTSignatureECFailsForIncorrectVersion(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sct := sigTestSCTEC(t)
sct.SCTVersion++
expectVerifySCTToFail(t, v, sct, "Incorrectly verified signature with incorrect SCT Version.")
}
func TestVerifySCTSignatureECFailsForIncorrectSignature(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
testVerifySCTSignatureFailsForIncorrectSignature(t, sigTestSCTEC(t), v)
}
func TestVerifySCTSignatureRSAFailsForIncorrectLeafBytes(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestRSAPublicKey(t))
testVerifySCTSignatureFailsForIncorrectLeafBytes(t, sigTestSCTRSA(t), v)
}
func TestVerifySCTSignatureRSAFailsForIncorrectSignature(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestRSAPublicKey(t))
testVerifySCTSignatureFailsForIncorrectSignature(t, sigTestSCTRSA(t), v)
}
func TestVerifySCTSignatureFailsForSignatureCreatedWithDifferentAlgorithm(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestRSAPublicKey(t))
testVerifySCTSignatureFailsForIncorrectSignature(t, sigTestSCTEC(t), v)
}
func TestVerifySCTSignatureFailsForSignatureCreatedWithDifferentKey(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey2(t))
testVerifySCTSignatureFailsForIncorrectSignature(t, sigTestSCTEC(t), v)
}
func expectVerifySTHToPass(t *testing.T, v SignatureVerifier, sth SignedTreeHead) {
t.Helper()
if err := v.VerifySTHSignature(sth); err != nil {
t.Fatalf("Incorrectly failed to verify STH signature: %v", err)
}
}
func expectVerifySTHToFail(t *testing.T, v SignatureVerifier, sth SignedTreeHead) {
t.Helper()
if err := v.VerifySTHSignature(sth); err == nil {
t.Fatal("Incorrectly verified STH signature")
}
}
func TestVerifyValidSTH(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sth := sigTestDefaultSTH(t)
expectVerifySTHToPass(t, v, sth)
}
func TestVerifySTHCatchesCorruptSignature(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sth := sigTestDefaultSTH(t)
corruptBytes(sth.TreeHeadSignature.Signature)
expectVerifySTHToFail(t, v, sth)
}
func TestVerifySTHCatchesCorruptRootHash(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sth := sigTestDefaultSTH(t)
for i := range sth.SHA256RootHash {
old := sth.SHA256RootHash[i]
corruptByteAt(sth.SHA256RootHash[:], i)
expectVerifySTHToFail(t, v, sth)
sth.SHA256RootHash[i] = old
}
// ensure we were only testing one corrupt byte at a time - should be correct again now.
expectVerifySTHToPass(t, v, sth)
}
func TestVerifySTHCatchesCorruptTimestamp(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sth := sigTestDefaultSTH(t)
sth.Timestamp++
expectVerifySTHToFail(t, v, sth)
}
func TestVerifySTHCatchesCorruptVersion(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sth := sigTestDefaultSTH(t)
sth.Version++
expectVerifySTHToFail(t, v, sth)
}
func TestVerifySTHCatchesCorruptTreeSize(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey(t))
sth := sigTestDefaultSTH(t)
sth.TreeSize++
expectVerifySTHToFail(t, v, sth)
}
func TestVerifySTHFailsToVerifyForKeyWithDifferentAlgorithm(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestRSAPublicKey(t))
sth := sigTestDefaultSTH(t)
expectVerifySTHToFail(t, v, sth)
}
func TestVerifySTHFailsToVerifyForDifferentKey(t *testing.T) {
v := mustCreateSignatureVerifier(t, sigTestECPublicKey2(t))
sth := sigTestDefaultSTH(t)
expectVerifySTHToFail(t, v, sth)
}
func TestNewSignatureVerifierFailsWithUnsupportedKeyType(t *testing.T) {
var k dsa.PrivateKey
if err := dsa.GenerateParameters(&k.Parameters, rand.Reader, dsa.L1024N160); err != nil {
t.Fatalf("Failed to generate DSA key parameters: %v", err)
}
if err := dsa.GenerateKey(&k, rand.Reader); err != nil {
t.Fatalf("Failed to generate DSA key: %v", err)
}
if _, err := NewSignatureVerifier(k); err == nil {
t.Fatal("Creating a SignatureVerifier with a DSA key unexpectedly succeeded")
}
}
func TestNewSignatureVerifierFailsWithBadKeyParametersForEC(t *testing.T) {
k, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
if err != nil {
t.Fatalf("Failed to generate ECDSA key on P224: %v", err)
}
if _, err := NewSignatureVerifier(k); err == nil {
t.Fatal("Incorrectly created new SignatureVerifier with EC P224 key.")
}
}
func TestNewSignatureVerifierFailsWithBadKeyParametersForRSA(t *testing.T) {
k, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
t.Fatalf("Failed to generate 1024 bit RSA key: %v", err)
}
if _, err := NewSignatureVerifier(k); err == nil {
t.Fatal("Incorrectly created new SignatureVerifier with 1024 bit RSA key.")
}
}
func TestWillAllowNonCompliantECKeyWithOverride(t *testing.T) {
AllowVerificationWithNonCompliantKeys = true
k, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
if err != nil {
t.Fatalf("Failed to generate EC key on P224: %v", err)
}
if _, err := NewSignatureVerifier(k.Public()); err != nil {
t.Fatalf("Incorrectly disallowed P224 EC key with override set: %v", err)
}
}
func TestWillAllowNonCompliantRSAKeyWithOverride(t *testing.T) {
AllowVerificationWithNonCompliantKeys = true
k, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
t.Fatalf("Failed to generate 1024 bit RSA key: %v", err)
}
if _, err := NewSignatureVerifier(k.Public()); err != nil {
t.Fatalf("Incorrectly disallowed 1024 bit RSA key with override set: %v", err)
}
}

View File

@ -1,30 +0,0 @@
shard {
uri: "https://ct.googleapis.com/logs/argon2017"
public_key_der:"0Y0\023\006\007*\206H\316=\002\001\006\010*\206H\316=\003\001\007\003B\000\004Tm|\211\335\352\235\360\272_\364m`z7O\002%\277\034\366o\205\256\257\025\337in\355\333\251\232)\227\362\231v\036\3463F\036'\364\276p\335Y\327\272\317\376\320r\216\260W\017\2357\211b\243"
not_after_start:<seconds:1483228800>
not_after_limit:<seconds:1514764800>
}
shard {
uri: "https://ct.googleapis.com/logs/argon2018"
public_key_der:"0Y0\023\006\007*\206H\316=\002\001\006\010*\206H\316=\003\001\007\003B\000\004\322\000U\005\255\325G\264\031\273\315\225\373)\327X=x$\315\316F\235\3732\324qN`\002%^Y>\327\324\003\270mChh~\350\240e\013>nqY\2227\276\251\350\361\243+\344\331\rUh"
not_after_start:<seconds:1514764800>
not_after_limit:<seconds:1546300800>
}
shard {
uri: "https://ct.googleapis.com/logs/argon2019"
public_key_der:"0Y0\023\006\007*\206H\316=\002\001\006\010*\206H\316=\003\001\007\003B\000\004#s\020\233\341\363^\366\230ki\225\226\020x\316I\333\264\004\374q,Z\222`h%\300J\032\241\260a-\033\207\024\251\272\360\0013Y\035\0050\351B\025\347U\327*\370\264\242\272E\311F\221\207V"
not_after_start:<seconds:1546300800>
not_after_limit:<seconds:1577836800>
}
shard {
uri: "https://ct.googleapis.com/logs/argon2020"
public_key_der:"0Y0\023\006\007*\206H\316=\002\001\006\010*\206H\316=\003\001\007\003B\000\004\351<v\247\\\212c\2155\344\334\210b\367k\223~\236\263K\200s\\\300\340\364>LdX\373vcQ2\030c\325\262\273\355\352\377^;$n/5R\213\2645\232\255\234\025\250i \352P\030\314"
not_after_start:<seconds:1577836800>
not_after_limit:<seconds:1609459200>
}
shard {
uri: "https://ct.googleapis.com/logs/argon2021"
public_key_der:"0Y0\023\006\007*\206H\316=\002\001\006\010*\206H\316=\003\001\007\003B\000\004M\340fd\352\363d\2528\305\211-\307\330\010\331\310Dq\355\334\303\373[\257\234d\241\tf\204\035|h\247\354\304?\214\234\202\340\030\331t\024\351\264y\201\242\224Ub\363\234\013D\203\241+\311q+"
not_after_start:<seconds:1609459200>
not_after_limit:<seconds:1640995200>
}

View File

@ -1,409 +0,0 @@
// 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 testdata
import (
"encoding/hex"
)
const (
// CACertPEM is a CA cert:
// Certificate:
// Data:
// Version: 3 (0x2)
// Serial Number: 0 (0x0)
// Signature Algorithm: sha1WithRSAEncryption
// Issuer: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen
// Validity
// Not Before: Jun 1 00:00:00 2012 GMT
// Not After : Jun 1 00:00:00 2022 GMT
// Subject: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen
// Subject Public Key Info:
// Public Key Algorithm: rsaEncryption
// Public-Key: (1024 bit)
// Modulus:
// 00:d5:8a:68:53:62:10:a2:71:19:93:6e:77:83:21:
// 18:1c:2a:40:13:c6:d0:7b:8c:76:eb:91:57:d3:d0:
// fb:4b:3b:51:6e:ce:cb:d1:c9:8d:91:c5:2f:74:3f:
// ab:63:5d:55:09:9c:d1:3a:ba:f3:1a:e5:41:44:24:
// 51:a7:4c:78:16:f2:24:3c:f8:48:cf:28:31:cc:e6:
// 7b:a0:4a:5a:23:81:9f:3c:ba:37:e6:24:d9:c3:bd:
// b2:99:b8:39:dd:fe:26:31:d2:cb:3a:84:fc:7b:b2:
// b5:c5:2f:cf:c1:4f:ff:40:6f:5c:d4:46:69:cb:b2:
// f7:cf:df:86:fb:6a:b9:d1:b1
// Exponent: 65537 (0x10001)
// X509v3 extensions:
// X509v3 Subject Key Identifier:
// 5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55
// X509v3 Authority Key Identifier:
// keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55
// DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen
// serial:00
//
// X509v3 Basic Constraints:
// CA:TRUE
// Signature Algorithm: sha1WithRSAEncryption
// 06:08:cc:4a:6d:64:f2:20:5e:14:6c:04:b2:76:f9:2b:0e:fa:
// 94:a5:da:f2:3a:fc:38:06:60:6d:39:90:d0:a1:ea:23:3d:40:
// 29:57:69:46:3b:04:66:61:e7:fa:1d:17:99:15:20:9a:ea:2e:
// 0a:77:51:76:41:12:27:d7:c0:03:07:c7:47:0e:61:58:4f:d7:
// 33:42:24:72:7f:51:d6:90:bc:47:a9:df:35:4d:b0:f6:eb:25:
// 95:5d:e1:89:3c:4d:d5:20:2b:24:a2:f3:e4:40:d2:74:b5:4e:
// 1b:d3:76:26:9c:a9:62:89:b7:6e:ca:a4:10:90:e1:4f:3b:0a:
// 94:2e
CACertPEM = "-----BEGIN CERTIFICATE-----\n" +
"MIIC0DCCAjmgAwIBAgIBADANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n" +
"MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX\n" +
"YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw\n" +
"MDAwMDBaMFUxCzAJBgNVBAYTAkdCMSQwIgYDVQQKExtDZXJ0aWZpY2F0ZSBUcmFu\n" +
"c3BhcmVuY3kgQ0ExDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGf\n" +
"MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVimhTYhCicRmTbneDIRgcKkATxtB7\n" +
"jHbrkVfT0PtLO1FuzsvRyY2RxS90P6tjXVUJnNE6uvMa5UFEJFGnTHgW8iQ8+EjP\n" +
"KDHM5nugSlojgZ88ujfmJNnDvbKZuDnd/iYx0ss6hPx7srXFL8/BT/9Ab1zURmnL\n" +
"svfP34b7arnRsQIDAQABo4GvMIGsMB0GA1UdDgQWBBRfnYgNyHPmVNT4DdjmsMEk\n" +
"tEfDVTB9BgNVHSMEdjB0gBRfnYgNyHPmVNT4DdjmsMEktEfDVaFZpFcwVTELMAkG\n" +
"A1UEBhMCR0IxJDAiBgNVBAoTG0NlcnRpZmljYXRlIFRyYW5zcGFyZW5jeSBDQTEO\n" +
"MAwGA1UECBMFV2FsZXMxEDAOBgNVBAcTB0VydyBXZW6CAQAwDAYDVR0TBAUwAwEB\n" +
"/zANBgkqhkiG9w0BAQUFAAOBgQAGCMxKbWTyIF4UbASydvkrDvqUpdryOvw4BmBt\n" +
"OZDQoeojPUApV2lGOwRmYef6HReZFSCa6i4Kd1F2QRIn18ADB8dHDmFYT9czQiRy\n" +
"f1HWkLxHqd81TbD26yWVXeGJPE3VICskovPkQNJ0tU4b03YmnKliibduyqQQkOFP\n" +
"OwqULg==\n" +
"-----END CERTIFICATE-----"
// TestCertPEM is a leaf certificate signed by CACertPEM.
// Certificate:
// Data:
// Version: 3 (0x2)
// Serial Number: 6 (0x6)
// Signature Algorithm: sha1WithRSAEncryption
// Issuer: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen
// Validity
// Not Before: Jun 1 00:00:00 2012 GMT
// Not After : Jun 1 00:00:00 2022 GMT
// Subject: C=GB, O=Certificate Transparency, ST=Wales, L=Erw Wen
// Subject Public Key Info:
// Public Key Algorithm: rsaEncryption
// Public-Key: (1024 bit)
// Modulus:
// 00:b1:fa:37:93:61:11:f8:79:2d:a2:08:1c:3f:e4:
// 19:25:00:85:31:dc:7f:2c:65:7b:d9:e1:de:47:04:
// 16:0b:4c:9f:19:d5:4a:da:44:70:40:4c:1c:51:34:
// 1b:8f:1f:75:38:dd:dd:28:d9:ac:a4:83:69:fc:56:
// 46:dd:cc:76:17:f8:16:8a:ae:5b:41:d4:33:31:fc:
// a2:da:df:c8:04:d5:72:08:94:90:61:f9:ee:f9:02:
// ca:47:ce:88:c6:44:e0:00:f0:6e:ee:cc:ab:dc:9d:
// d2:f6:8a:22:cc:b0:9d:c7:6e:0d:bc:73:52:77:65:
// b1:a3:7a:8c:67:62:53:dc:c1
// Exponent: 65537 (0x10001)
// X509v3 extensions:
// X509v3 Subject Key Identifier:
// 6A:0D:98:2A:3B:62:C4:4B:6D:2E:F4:E9:BB:7A:01:AA:9C:B7:98:E2
// X509v3 Authority Key Identifier:
// keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55
// DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen
// serial:00
//
// X509v3 Basic Constraints:
// CA:FALSE
// Signature Algorithm: sha1WithRSAEncryption
// 17:1c:d8:4a:ac:41:4a:9a:03:0f:22:aa:c8:f6:88:b0:81:b2:
// 70:9b:84:8b:4e:55:11:40:6c:d7:07:fe:d0:28:59:7a:9f:ae:
// fc:2e:ee:29:78:d6:33:aa:ac:14:ed:32:35:19:7d:a8:7e:0f:
// 71:b8:87:5f:1a:c9:e7:8b:28:17:49:dd:ed:d0:07:e3:ec:f5:
// 06:45:f8:cb:f6:67:25:6c:d6:a1:64:7b:5e:13:20:3b:b8:58:
// 2d:e7:d6:69:6f:65:6d:1c:60:b9:5f:45:6b:7f:cf:33:85:71:
// 90:8f:1c:69:72:7d:24:c4:fc:cd:24:92:95:79:58:14:d1:da:
// c0:e6
TestCertPEM = "-----BEGIN CERTIFICATE-----\n" +
"MIICyjCCAjOgAwIBAgIBBjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n" +
"MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX\n" +
"YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw\n" +
"MDAwMDBaMFIxCzAJBgNVBAYTAkdCMSEwHwYDVQQKExhDZXJ0aWZpY2F0ZSBUcmFu\n" +
"c3BhcmVuY3kxDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGfMA0G\n" +
"CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx+jeTYRH4eS2iCBw/5BklAIUx3H8sZXvZ\n" +
"4d5HBBYLTJ8Z1UraRHBATBxRNBuPH3U43d0o2aykg2n8VkbdzHYX+BaKrltB1DMx\n" +
"/KLa38gE1XIIlJBh+e75AspHzojGROAA8G7uzKvcndL2iiLMsJ3Hbg28c1J3ZbGj\n" +
"eoxnYlPcwQIDAQABo4GsMIGpMB0GA1UdDgQWBBRqDZgqO2LES20u9Om7egGqnLeY\n" +
"4jB9BgNVHSMEdjB0gBRfnYgNyHPmVNT4DdjmsMEktEfDVaFZpFcwVTELMAkGA1UE\n" +
"BhMCR0IxJDAiBgNVBAoTG0NlcnRpZmljYXRlIFRyYW5zcGFyZW5jeSBDQTEOMAwG\n" +
"A1UECBMFV2FsZXMxEDAOBgNVBAcTB0VydyBXZW6CAQAwCQYDVR0TBAIwADANBgkq\n" +
"hkiG9w0BAQUFAAOBgQAXHNhKrEFKmgMPIqrI9oiwgbJwm4SLTlURQGzXB/7QKFl6\n" +
"n678Lu4peNYzqqwU7TI1GX2ofg9xuIdfGsnniygXSd3t0Afj7PUGRfjL9mclbNah\n" +
"ZHteEyA7uFgt59Zpb2VtHGC5X0Vrf88zhXGQjxxpcn0kxPzNJJKVeVgU0drA5g==\n" +
"-----END CERTIFICATE-----\n"
// TestPreCertPEM is a pre-certificate signed by CACertPEM.
// Certificate:
// Data:
// Version: 3 (0x2)
// Serial Number: 7 (0x7)
// Signature Algorithm: sha1WithRSAEncryption
// Issuer: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen
// Validity
// Not Before: Jun 1 00:00:00 2012 GMT
// Not After : Jun 1 00:00:00 2022 GMT
// Subject: C=GB, O=Certificate Transparency, ST=Wales, L=Erw Wen
// Subject Public Key Info:
// Public Key Algorithm: rsaEncryption
// Public-Key: (1024 bit)
// Modulus:
// 00:be:ef:98:e7:c2:68:77:ae:38:5f:75:32:5a:0c:
// 1d:32:9b:ed:f1:8f:aa:f4:d7:96:bf:04:7e:b7:e1:
// ce:15:c9:5b:a2:f8:0e:e4:58:bd:7d:b8:6f:8a:4b:
// 25:21:91:a7:9b:d7:00:c3:8e:9c:03:89:b4:5c:d4:
// dc:9a:12:0a:b2:1e:0c:b4:1c:d0:e7:28:05:a4:10:
// cd:9c:5b:db:5d:49:27:72:6d:af:17:10:f6:01:87:
// 37:7e:a2:5b:1a:1e:39:ee:d0:b8:81:19:dc:15:4d:
// c6:8f:7d:a8:e3:0c:af:15:8a:33:e6:c9:50:9f:4a:
// 05:b0:14:09:ff:5d:d8:7e:b5
// Exponent: 65537 (0x10001)
// X509v3 extensions:
// X509v3 Subject Key Identifier:
// 20:31:54:1A:F2:5C:05:FF:D8:65:8B:68:43:79:4F:5E:90:36:F7:B4
// X509v3 Authority Key Identifier:
// keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55
// DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen
// serial:00
//
// X509v3 Basic Constraints:
// CA:FALSE
// 1.3.6.1.4.1.11129.2.4.3: critical
// ..
// Signature Algorithm: sha1WithRSAEncryption
// 02:a1:c3:9e:01:5a:f5:4d:ff:02:3c:33:60:87:5f:ff:34:37:
// 55:2f:1f:09:01:bd:c2:54:31:5f:33:72:b7:23:fb:15:fb:ce:
// cc:4d:f4:71:a0:ce:4d:8c:54:65:5d:84:87:97:fb:28:1e:3d:
// fa:bb:46:2d:2c:68:4b:05:6f:ea:7b:63:b4:70:ff:16:6e:32:
// d4:46:06:35:b3:d2:bc:6d:a8:24:9b:26:30:e7:1f:c3:4f:08:
// f2:3d:d4:ee:22:8f:8f:74:f6:3d:78:63:11:dd:0a:58:11:40:
// 5f:90:6c:ca:2c:2d:3e:eb:fc:81:99:64:eb:d8:cf:7c:08:86:
// 3f:be
TestPreCertPEM = "-----BEGIN CERTIFICATE-----\n" +
"MIIC3zCCAkigAwIBAgIBBzANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n" +
"MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX\n" +
"YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw\n" +
"MDAwMDBaMFIxCzAJBgNVBAYTAkdCMSEwHwYDVQQKExhDZXJ0aWZpY2F0ZSBUcmFu\n" +
"c3BhcmVuY3kxDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGfMA0G\n" +
"CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+75jnwmh3rjhfdTJaDB0ym+3xj6r015a/\n" +
"BH634c4VyVui+A7kWL19uG+KSyUhkaeb1wDDjpwDibRc1NyaEgqyHgy0HNDnKAWk\n" +
"EM2cW9tdSSdyba8XEPYBhzd+olsaHjnu0LiBGdwVTcaPfajjDK8VijPmyVCfSgWw\n" +
"FAn/Xdh+tQIDAQABo4HBMIG+MB0GA1UdDgQWBBQgMVQa8lwF/9hli2hDeU9ekDb3\n" +
"tDB9BgNVHSMEdjB0gBRfnYgNyHPmVNT4DdjmsMEktEfDVaFZpFcwVTELMAkGA1UE\n" +
"BhMCR0IxJDAiBgNVBAoTG0NlcnRpZmljYXRlIFRyYW5zcGFyZW5jeSBDQTEOMAwG\n" +
"A1UECBMFV2FsZXMxEDAOBgNVBAcTB0VydyBXZW6CAQAwCQYDVR0TBAIwADATBgor\n" +
"BgEEAdZ5AgQDAQH/BAIFADANBgkqhkiG9w0BAQUFAAOBgQACocOeAVr1Tf8CPDNg\n" +
"h1//NDdVLx8JAb3CVDFfM3K3I/sV+87MTfRxoM5NjFRlXYSHl/soHj36u0YtLGhL\n" +
"BW/qe2O0cP8WbjLURgY1s9K8bagkmyYw5x/DTwjyPdTuIo+PdPY9eGMR3QpYEUBf\n" +
"kGzKLC0+6/yBmWTr2M98CIY/vg==\n" +
"-----END CERTIFICATE-----\n"
// TestEmbeddedCertPEM is a certificate containing an embedded SCT that
// corresponds to TestPreCertProof.
// Certificate:
// Data:
// Version: 3 (0x2)
// Serial Number: 7 (0x7)
// Signature Algorithm: sha1WithRSAEncryption
// Issuer: C = GB, O = Certificate Transparency CA, ST = Wales, L = Erw Wen
// Validity
// Not Before: Jun 1 00:00:00 2012 GMT
// Not After : Jun 1 00:00:00 2022 GMT
// Subject: C = GB, O = Certificate Transparency, ST = Wales, L = Erw Wen
// Subject Public Key Info:
// Public Key Algorithm: rsaEncryption
// Public-Key: (1024 bit)
// Modulus:
// 00:be:ef:98:e7:c2:68:77:ae:38:5f:75:32:5a:0c:
// 1d:32:9b:ed:f1:8f:aa:f4:d7:96:bf:04:7e:b7:e1:
// ce:15:c9:5b:a2:f8:0e:e4:58:bd:7d:b8:6f:8a:4b:
// 25:21:91:a7:9b:d7:00:c3:8e:9c:03:89:b4:5c:d4:
// dc:9a:12:0a:b2:1e:0c:b4:1c:d0:e7:28:05:a4:10:
// cd:9c:5b:db:5d:49:27:72:6d:af:17:10:f6:01:87:
// 37:7e:a2:5b:1a:1e:39:ee:d0:b8:81:19:dc:15:4d:
// c6:8f:7d:a8:e3:0c:af:15:8a:33:e6:c9:50:9f:4a:
// 05:b0:14:09:ff:5d:d8:7e:b5
// Exponent: 65537 (0x10001)
// X509v3 extensions:
// X509v3 Subject Key Identifier:
// 20:31:54:1A:F2:5C:05:FF:D8:65:8B:68:43:79:4F:5E:90:36:F7:B4
// X509v3 Authority Key Identifier:
// keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55
// DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen
// serial:00
//
// X509v3 Basic Constraints:
// CA:FALSE
// CT Precertificate SCTs:
// Signed Certificate Timestamp:
// Version : v1 (0x0)
// Log ID : DF:1C:2E:C1:15:00:94:52:47:A9:61:68:32:5D:DC:5C:
// 79:59:E8:F7:C6:D3:88:FC:00:2E:0B:BD:3F:74:D7:64
// Timestamp : Apr 5 17:04:16.275 2013 GMT
// Extensions: none
// Signature : ecdsa-with-SHA256
// 30:45:02:20:48:2F:67:51:AF:35:DB:A6:54:36:BE:1F:
// D6:64:0F:3D:BF:9A:41:42:94:95:92:45:30:28:8F:A3:
// E5:E2:3E:06:02:21:00:E4:ED:C0:DB:3A:C5:72:B1:E2:
// F5:E8:AB:6A:68:06:53:98:7D:CF:41:02:7D:FE:FF:A1:
// 05:51:9D:89:ED:BF:08
// Signature Algorithm: sha1WithRSAEncryption
// 8a:0c:4b:ef:09:9d:47:92:79:af:a0:a2:8e:68:9f:91:e1:c4:
// 42:1b:e2:d2:69:a2:ea:6c:a4:e8:21:5d:de:dd:ca:15:04:a1:
// 1e:7c:87:c4:b7:7e:80:f0:e9:79:03:52:68:f2:7c:a2:0e:16:
// 68:04:ae:55:6f:31:69:81:f9:6a:39:4a:b7:ab:fd:3e:25:5a:
// c0:04:45:13:fe:76:57:0c:67:95:ab:e4:70:31:33:d3:03:f8:
// 9f:3a:fa:6b:bc:fc:51:73:19:df:d9:5b:93:42:41:21:1f:63:
// 40:35:c3:d0:78:30:7a:68:c6:07:5a:2e:20:c8:9f:36:b8:91:
// 0c:a0
TestEmbeddedCertPEM = "-----BEGIN CERTIFICATE-----\n" +
"MIIDWTCCAsKgAwIBAgIBBzANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n" +
"MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX\n" +
"YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw\n" +
"MDAwMDBaMFIxCzAJBgNVBAYTAkdCMSEwHwYDVQQKExhDZXJ0aWZpY2F0ZSBUcmFu\n" +
"c3BhcmVuY3kxDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGfMA0G\n" +
"CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+75jnwmh3rjhfdTJaDB0ym+3xj6r015a/\n" +
"BH634c4VyVui+A7kWL19uG+KSyUhkaeb1wDDjpwDibRc1NyaEgqyHgy0HNDnKAWk\n" +
"EM2cW9tdSSdyba8XEPYBhzd+olsaHjnu0LiBGdwVTcaPfajjDK8VijPmyVCfSgWw\n" +
"FAn/Xdh+tQIDAQABo4IBOjCCATYwHQYDVR0OBBYEFCAxVBryXAX/2GWLaEN5T16Q\n" +
"Nve0MH0GA1UdIwR2MHSAFF+diA3Ic+ZU1PgN2OawwSS0R8NVoVmkVzBVMQswCQYD\n" +
"VQQGEwJHQjEkMCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4w\n" +
"DAYDVQQIEwVXYWxlczEQMA4GA1UEBxMHRXJ3IFdlboIBADAJBgNVHRMEAjAAMIGK\n" +
"BgorBgEEAdZ5AgQCBHwEegB4AHYA3xwuwRUAlFJHqWFoMl3cXHlZ6PfG04j8AC4L\n" +
"vT9012QAAAE92yffkwAABAMARzBFAiBIL2dRrzXbplQ2vh/WZA89v5pBQpSVkkUw\n" +
"KI+j5eI+BgIhAOTtwNs6xXKx4vXoq2poBlOYfc9BAn3+/6EFUZ2J7b8IMA0GCSqG\n" +
"SIb3DQEBBQUAA4GBAIoMS+8JnUeSea+goo5on5HhxEIb4tJpoupspOghXd7dyhUE\n" +
"oR58h8S3foDw6XkDUmjyfKIOFmgErlVvMWmB+Wo5Srer/T4lWsAERRP+dlcMZ5Wr\n" +
"5HAxM9MD+J86+mu8/FFzGd/ZW5NCQSEfY0A1w9B4MHpoxgdaLiDInza4kQyg\n" +
"-----END CERTIFICATE-----\n"
// TestInvalidEmbeddedCertPEM is a certificate that contains an SCT that is
// not for the corresponding pre-certificate. The SCT embedded corresponds
// to TestInvalidProof.
// Certificate:
// Data:
// Version: 3 (0x2)
// Serial Number: 7 (0x7)
// Signature Algorithm: sha1WithRSAEncryption
// Issuer: C = GB, O = Certificate Transparency CA, ST = Wales, L = Erw Wen
// Validity
// Not Before: Jun 1 00:00:00 2012 GMT
// Not After : Jun 1 00:00:00 2022 GMT
// Subject: C = GB, O = Certificate Transparency, ST = Wales, L = Erw Wen
// Subject Public Key Info:
// Public Key Algorithm: rsaEncryption
// Public-Key: (1024 bit)
// Modulus:
// 00:be:ef:98:e7:c2:68:77:ae:38:5f:75:32:5a:0c:
// 1d:32:9b:ed:f1:8f:aa:f4:d7:96:bf:04:7e:b7:e1:
// ce:15:c9:5b:a2:f8:0e:e4:58:bd:7d:b8:6f:8a:4b:
// 25:21:91:a7:9b:d7:00:c3:8e:9c:03:89:b4:5c:d4:
// dc:9a:12:0a:b2:1e:0c:b4:1c:d0:e7:28:05:a4:10:
// cd:9c:5b:db:5d:49:27:72:6d:af:17:10:f6:01:87:
// 37:7e:a2:5b:1a:1e:39:ee:d0:b8:81:19:dc:15:4d:
// c6:8f:7d:a8:e3:0c:af:15:8a:33:e6:c9:50:9f:4a:
// 05:b0:14:09:ff:5d:d8:7e:b5
// Exponent: 65537 (0x10001)
// X509v3 extensions:
// X509v3 Subject Key Identifier:
// 20:31:54:1A:F2:5C:05:FF:D8:65:8B:68:43:79:4F:5E:90:36:F7:B4
// X509v3 Authority Key Identifier:
// keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55
// DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen
// serial:00
//
// X509v3 Basic Constraints:
// CA:FALSE
// CT Precertificate SCTs:
// Signed Certificate Timestamp:
// Version : v1 (0x0)
// Log ID : DF:1C:2E:C1:15:00:94:52:47:A9:61:68:32:5D:DC:5C:
// 79:59:E8:F7:C6:D3:88:FC:00:2E:0B:BD:3F:74:D7:64
// Timestamp : Apr 5 17:04:17.060 2013 GMT
// Extensions: none
// Signature : ecdsa-with-SHA256
// 30:45:02:21:00:A6:D3:45:17:F3:39:2D:9E:C5:D2:57:
// AD:F1:C5:97:DC:45:BD:4C:D3:B7:38:56:C6:16:A9:FB:
// 99:E5:AE:75:A8:02:20:5E:26:C8:D1:C7:E2:22:FE:8C:
// DA:29:BA:EB:04:A8:34:EE:97:D3:4F:D8:17:18:F1:AA:
// E0:CD:66:F4:B8:A9:3F
// Signature Algorithm: sha1WithRSAEncryption
// af:28:89:06:38:b0:12:6f:dd:64:5d:d0:62:80:f8:10:6c:ec:
// 49:4c:f8:22:86:0a:29:d4:f1:7e:6a:a5:7c:5a:58:b2:96:cc:
// 90:c6:db:f1:22:10:4b:7f:4a:76:d6:fd:df:f2:1a:41:3a:9e:
// e7:88:7e:32:a3:c7:a2:07:3c:e6:af:ae:01:b4:1a:a2:3d:ce:
// 98:f3:ab:5e:c7:5c:e7:59:fa:7c:cc:ab:4f:fa:7a:a7:3e:7d:
// 98:38:77:c6:d0:f1:de:cd:dd:37:49:00:59:b7:91:90:b2:7f:
// 85:94:2b:7c:c8:b2:3c:bf:90:30:68:5d:21:43:c4:95:a5:39:
// 6d:9f
TestInvalidEmbeddedCertPEM = "-----BEGIN CERTIFICATE-----\n" +
"MIIDWTCCAsKgAwIBAgIBBzANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk\n" +
"MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX\n" +
"YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw\n" +
"MDAwMDBaMFIxCzAJBgNVBAYTAkdCMSEwHwYDVQQKExhDZXJ0aWZpY2F0ZSBUcmFu\n" +
"c3BhcmVuY3kxDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGfMA0G\n" +
"CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+75jnwmh3rjhfdTJaDB0ym+3xj6r015a/\n" +
"BH634c4VyVui+A7kWL19uG+KSyUhkaeb1wDDjpwDibRc1NyaEgqyHgy0HNDnKAWk\n" +
"EM2cW9tdSSdyba8XEPYBhzd+olsaHjnu0LiBGdwVTcaPfajjDK8VijPmyVCfSgWw\n" +
"FAn/Xdh+tQIDAQABo4IBOjCCATYwHQYDVR0OBBYEFCAxVBryXAX/2GWLaEN5T16Q\n" +
"Nve0MH0GA1UdIwR2MHSAFF+diA3Ic+ZU1PgN2OawwSS0R8NVoVmkVzBVMQswCQYD\n" +
"VQQGEwJHQjEkMCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4w\n" +
"DAYDVQQIEwVXYWxlczEQMA4GA1UEBxMHRXJ3IFdlboIBADAJBgNVHRMEAjAAMIGK\n" +
"BgorBgEEAdZ5AgQCBHwEegB4AHYA3xwuwRUAlFJHqWFoMl3cXHlZ6PfG04j8AC4L\n" +
"vT9012QAAAE92yfipAAABAMARzBFAiEAptNFF/M5LZ7F0let8cWX3EW9TNO3OFbG\n" +
"Fqn7meWudagCIF4myNHH4iL+jNopuusEqDTul9NP2BcY8argzWb0uKk/MA0GCSqG\n" +
"SIb3DQEBBQUAA4GBAK8oiQY4sBJv3WRd0GKA+BBs7ElM+CKGCinU8X5qpXxaWLKW\n" +
"zJDG2/EiEEt/SnbW/d/yGkE6nueIfjKjx6IHPOavrgG0GqI9zpjzq17HXOdZ+nzM\n" +
"q0/6eqc+fZg4d8bQ8d7N3TdJAFm3kZCyf4WUK3zIsjy/kDBoXSFDxJWlOW2f\n" +
"-----END CERTIFICATE-----\n"
)
var (
// TestCertProof is a TLS-encoded ct.SignedCertificateTimestamp corresponding
// to TestCertPEM.
TestCertProof = dh("00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7" +
"640000013ddb27ded900000403004730450220606e10ae5c2d5a1b0aed49dc49" +
"37f48de71a4e9784e9c208dfbfe9ef536cf7f2022100beb29c72d7d06d61d06b" +
"db38a069469aa86fe12e18bb7cc45689a2c0187ef5a5")
// TestPreCertProof is a TLS-encoded ct.SignedCertificateTimestamp
// corresponding to TestPreCertPEM
TestPreCertProof = dh("00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7" +
"640000013ddb27df9300000403004730450220482f6751af35dba65436be1fd6" +
"640f3dbf9a41429495924530288fa3e5e23e06022100e4edc0db3ac572b1e2f5" +
"e8ab6a680653987dcf41027dfeffa105519d89edbf08")
// TestInvalidProof is a TLS-encoded ct.SignedCertificateTimestamp
// corresponding to the invalid SCT embedded in TestInvalidEmbeddedCertPEM.
TestInvalidProof = dh("00df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d7" +
"640000013ddb27e2a40000040300473045022100a6d34517f3392d9ec5d257ad" +
"f1c597dc45bd4cd3b73856c616a9fb99e5ae75a802205e26c8d1c7e222fe8cda" +
"29baeb04a834ee97d34fd81718f1aae0cd66f4b8a93f")
// TestCertB64LeafHash is the base64-encoded leaf hash of TestCertPEM with
// TestCertProof as the corresponding SCT.
TestCertB64LeafHash = "BKZLZGMbAnDW0gQWjNJNCyS2IgweWn76YW3tFlu3AuY="
// TestPreCertB64LeafHash is the base64-encoded leaf hash of TestPreCertPEM
// with TestPreCertProof as the corresponding SCT.
TestPreCertB64LeafHash = "mbk+d5FDW3oNZJCbOi828rqC3hf+qhigTWVGcXEZq1U="
)
func dh(h string) []byte {
r, err := hex.DecodeString(h)
if err != nil {
panic(err)
}
return r
}

View File

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

View File

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

View File

@ -1,221 +0,0 @@
// 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 testdata holds data and utility functions needed for various Go tests.
package testdata
import "encoding/hex"
// Hashes of text string 'abcd' with various algorithms; check with either "<alg>sum input" or "openssl dgst -<alg> input"
const (
// AbcdMD5 is 'abcd' hashed with MD5
AbcdMD5 = "e2fc714c4727ee9395f324cd2e7f331f"
// AbcdSHA1 is 'abcd' hashed with SHA1
AbcdSHA1 = "81fe8bfe87576c3ecb22426f8e57847382917acf"
// AbcdSHA224 is 'abcd' hashed with SHA224
AbcdSHA224 = "a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601"
// AbcdSHA256 is 'abcd' hashed with SHA256
AbcdSHA256 = "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589"
// AbcdSHA384 is 'abcd' hashed with SHA384
AbcdSHA384 = "1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b"
// AbcdSHA512 is 'abcd' hashed with SHA512
AbcdSHA512 = "d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f"
)
const (
// LogPublicKeyB64 is an ECDSA key copied from test/testdata/ct-server-key-public.pem
LogPublicKeyB64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmXg8sUUzwBYaWrRb+V0IopzQ6o3UyEJ04r5ZrRXGdpYM8K+hB0pXrGRLI0eeWz+3skXrS0IO83AhA3GpRL6s6w=="
// LogPublicKeyPEM is an ECDSA key copied from test/testdata/ct-server-key-public.pem
LogPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" +
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmXg8sUUzwBYaWrRb+V0IopzQ6o3U\n" +
"yEJ04r5ZrRXGdpYM8K+hB0pXrGRLI0eeWz+3skXrS0IO83AhA3GpRL6s6w==\n" +
"-----END PUBLIC KEY-----\n"
// RsaPrivateKeyPEM was generated with:
// openssl genpkey -algorithm RSA -out rsa.privkey.pem -pkeyopt rsa_keygen_bits:2048
RsaPrivateKeyPEM = "-----BEGIN PRIVATE KEY-----\n" +
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDP8SJM5SBIbFpF\n" +
"dRAUEERo35E4iFXfT5SVAzBIqATkCpf3LfdFZgssPeliBdTtgdvT/CWC2m6aVXYZ\n" +
"eScAJOauTpGDyJ7OXj7Yhx1q6u28NuQleU3UQK5QYb7VOjeIse7oTh+THf5IK5T5\n" +
"esyh+ioybEYBXXMQetHc4YbXAq06crNT2BP+AxQ4z27xu4X5CKLwwVMa2xwMCFDC\n" +
"Y7mxQzEhFv8+HbOtM0IQMSSyh6+o0w4Yzt6i/TUOytZb1D7WHOEMpVTd1CMbXjN0\n" +
"tFZvoO0V+n0OV3oT1E5AvwujVguUJblQiapbL890/nZbBtP3xMoFLLhc7sX7N2vR\n" +
"1wLWsjOVAgMBAAECggEBAL+frUZDV86l20JqsFhs7T3f2MnKCahyg7AWciZif69O\n" +
"e+BTQa14bg9lNm8YhLIim1vs3vyJIqei3eR3mxMs7k/vI3XYKVBv1WZgjSF8QXzS\n" +
"8Mf/01MoD/sPOHby4T5dCpaVd89xMmV7lBubqHwUN1KkKJcVcPXc2Qy94C6/zrcu\n" +
"Vb7Q91ugTvvhyalWEN02M3tzHEn4cXrnMLWPmTgxb7YtTMRIbJFx2um7/W9G5D+1\n" +
"ZtKMjwt+P/yXynx3Sa555MjjJ1/LUyMSbQZoLE0SGOigz1VQnP8nFlpvXUHzktiA\n" +
"IBPBBQSsEoS8H3z6WThwY72O795/i2l5mf7EUUAa2/kCgYEA+W7tJPg69KWHKn6E\n" +
"gGZKIDTxvp3vRxjLedp7D7cu6bVPCBVIHrPQdmp/mneY6x7Air0a9gCVbh32iCrm\n" +
"UrSBCio4i6jtqtna2T1Gc0z63K3UrVQPR0Z6Swq1XDOI6/I23ibxPr12/XXWWYlA\n" +
"wkPwvewJVrjtMoP1dkAKVbyzImcCgYEA1WqS0xg7BL4iNGFPrrSme2blZOgga83x\n" +
"CtY9dnWAs0IvdxsuItCDaFVJm3oU18ohirEMzqZvbRlwMlUawpd75hCNWyVF4cRo\n" +
"+l1RvzOlC/7QXX/E+Kv7sTEUYH7hJyS46QhOtC1/ndAyObk9c2VNJmERfMwIHNm9\n" +
"BfSN8yrq1KMCgYEA94fCZPbGIvSFj4EgYv+fvhhscvrucsLDYniTuUPTlXAtLttX\n" +
"x8gwLuN/ID5hjarl7oi90bVAlZe8iOLx0M96YykFFmuc9/jcOsuZN2EEbq0/KocJ\n" +
"5nSldgT5d7dYwLWNB6bjr5x8Egm3nwEbN+4OYZt0pRA9q+zSUfg5iV4K8y8CgYA7\n" +
"S9YposTbJ3zXcuYx022iQc+gvsIrUdgUO7xuCm3M4KnRfRLPh4HLXk8KTNw3rKiv\n" +
"IUw+qo2xEW1T/sNlp7M8FANCfNOyy+CjF4ScDFxiPdVk9RgkQ5y1+b4ApaAnQRPD\n" +
"Y5SCiVW44lziHu7M/it2a2fxdbsXUQQtAGrkUltW4wKBgAPZyEGi4V2wryOswmkC\n" +
"I29TbC6ChnUOvqJfSfz536eIi41D1Ua2Y/VlAK1ud7K8ilr/M4VoRjHqbPivR1Uk\n" +
"RU7nO3cWRBuDBjgZWeAq5WFIMPbm9gRlaTECI6EFtAOI1GcHOsOBecd3PBiQNXvj\n" +
"YyGD1wSrHQwDcnxtP1rqEQDV\n" +
"-----END PRIVATE KEY-----\n"
// RsaPublicKeyPEM was generated from above with:
// openssl rsa -pubout -in rsa.privkey.pem -out rsa.pubkey.pem
RsaPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" +
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz/EiTOUgSGxaRXUQFBBE\n" +
"aN+ROIhV30+UlQMwSKgE5AqX9y33RWYLLD3pYgXU7YHb0/wlgtpumlV2GXknACTm\n" +
"rk6Rg8iezl4+2IcdaurtvDbkJXlN1ECuUGG+1To3iLHu6E4fkx3+SCuU+XrMofoq\n" +
"MmxGAV1zEHrR3OGG1wKtOnKzU9gT/gMUOM9u8buF+Qii8MFTGtscDAhQwmO5sUMx\n" +
"IRb/Ph2zrTNCEDEksoevqNMOGM7eov01DsrWW9Q+1hzhDKVU3dQjG14zdLRWb6Dt\n" +
"Ffp9Dld6E9ROQL8Lo1YLlCW5UImqWy/PdP52WwbT98TKBSy4XO7F+zdr0dcC1rIz\n" +
"lQIDAQAB\n" +
"-----END PUBLIC KEY-----\n"
// RsaSignedAbcdHex was generated with:
// echo -n "abcd" > sign.input
// openssl sha256 -sign rsa.privkey.pem -out sign.rsa sign.input
// Verify with:
// openssl sha256 -verify rsa.pubkey.pem -signature sign.rsa sign.input
RsaSignedAbcdHex = "4692f17adad62324a38a786d9b05eb7facf95c277729bc23e8d4f4fe25c0ac0e" +
"9115f14ffd4dc6c00e6b2717677e96ed4da9e2226745db5c2d14ec8b4f96959e" +
"a43ca73e3ab801d4e76b0c0599c741b9701dd0c22b20cc7a294fccce97d2eda2" +
"72448830a19b0b1075f962d3bcf65922f81f4747dde1a2883ffce12941927af6" +
"25549ea7b4f745a95f5558822af434cc7471ea5a21cce656a7667d29bff3e6f2" +
"fb3d48bbee1a60116f0dd429d5691b008482e9ec42538bcf2692e1a685e836c8" +
"49316fb3c49b58bd5a0c33f0256b09d59af08a018fe64cd31051cb9e9a1d3fde" +
"e186bd80bfe304abbbec2ac18d3bee09465cb69f2638728aba4b9886a252768a"
// DsaPrivateKeyPEM was generated with:
// openssl dsaparam -out dsa.param.pem 2048; openssl gendsa dsa.param.pem -out dsa.privkey.pem
DsaPrivateKeyPEM = "-----BEGIN DSA PRIVATE KEY-----\n" +
"MIIDVwIBAAKCAQEA3Q72qQc0ZM2eUjvZ/XOROQTbhmjzuZdzY7kd+82n54NPeqVz\n" +
"+FWmk26INd7pUNbn/TjniN5+pC2pK+p9alFLE19bOvsY4x7Ugwrpd9sQIea3W4Q7\n" +
"H9PaEW+BooFzT/feC9TmnU0ynwoNhZB33Cr3k3PFt/69lmyrkd91wTpXrstrQurU\n" +
"h4baL5l6t2/JT3TxpKx6xe19hWqqFsBLu/j+kE2o2Aw1TVLHg4/74TJLfqAkWnCI\n" +
"u9QL0uGQnW80kRfJnT+tUJXrXMpg1HxK7CsDEW5xsAWF370Is0UPaP7jRru6FiSN\n" +
"ObcVhSqCIs+QJIWie9cRtwniwhoi4z6AfGeEYQIhAOkSzAsWja1fwB486/LCW+zv\n" +
"DJKiCGLTalimfawzHQHFAoIBAQDJvCujEZ/WeQFLlP/0zS+2DjqdaxnKj1xuXfoL\n" +
"LOocvMw06dnrQNmDu/nBQiYSfzf7zjwpnx+AVjBQssK0jXs0l7gw52FyCIztDejT\n" +
"/ybMVudwKUGudxAEjOclOSQ7XVpPd4p3UMy+E6pkJ8VRiuNFDibYTD+O3XhFTj2l\n" +
"6LqV/KcB2fWV1fUqfxax2vpcwe4clTJbJXUgJC3mYmUXv1U6z0hliDz2WMhbOyea\n" +
"1fs31zYvIMyk2wJFJl7+EbXb8BgYcQt1FE4c14fuFnincAW0So+xBZ5DtiTja4lm\n" +
"DE0OAI2hhLslSQ7rGwWt2zIKSFLtsWf78CP1wigJvWcUVhazAoIBAFAhxgtOaV8G\n" +
"FJxs6A3TtXEmmrq3i5/w3/8l7skWamcHvcwrvw37g5KQY+N+85JZszHPjmUzEq/o\n" +
"NOLjF6zq7+oRtWbOR3Mvc2hHsHg86tE/HAkBIu2G73c9UuskzGSMec4F6TyWKHvC\n" +
"26F2cvu9aA42v/8q1d/QQs3+LrtARGhyFCqnBVNSZmZj5ngR0kLGUfs/LQklpGFe\n" +
"VciXK57RxHSPo15lnKiHW9kCte7tGEg9Eber8paMz67dQDuj1yRkS5H7JXqRZjIP\n" +
"UrICWGGk1vluQsuoyI/Nu8/tL7Im24xZH6XHBm4F+aijl9XlAJiKXfkCLIaxYSdc\n" +
"4PXquTwtRLICIQCijrpD+UhidGFLPZCCLzBC239PrP7PabSVurWXHh5iYw==\n" +
"-----END DSA PRIVATE KEY-----\n"
// DsaPrivateKeyPKCS8PEM is a copy of the private key above, encoded in PKCS#8 format.
// Generated from above with:
// openssl pkcs8 -topk8 -nocrypt -in dsa.privkey.pem -out dsa.privkey.pkcs8.pem
DsaPrivateKeyPKCS8PEM = "-----BEGIN PRIVATE KEY-----\n" +
"MIICZgIBADCCAjoGByqGSM44BAEwggItAoIBAQDdDvapBzRkzZ5SO9n9c5E5BNuG\n" +
"aPO5l3NjuR37zafng096pXP4VaaTbog13ulQ1uf9OOeI3n6kLakr6n1qUUsTX1s6\n" +
"+xjjHtSDCul32xAh5rdbhDsf09oRb4GigXNP994L1OadTTKfCg2FkHfcKveTc8W3\n" +
"/r2WbKuR33XBOleuy2tC6tSHhtovmXq3b8lPdPGkrHrF7X2FaqoWwEu7+P6QTajY\n" +
"DDVNUseDj/vhMkt+oCRacIi71AvS4ZCdbzSRF8mdP61QletcymDUfErsKwMRbnGw\n" +
"BYXfvQizRQ9o/uNGu7oWJI05txWFKoIiz5AkhaJ71xG3CeLCGiLjPoB8Z4RhAiEA\n" +
"6RLMCxaNrV/AHjzr8sJb7O8MkqIIYtNqWKZ9rDMdAcUCggEBAMm8K6MRn9Z5AUuU\n" +
"//TNL7YOOp1rGcqPXG5d+gss6hy8zDTp2etA2YO7+cFCJhJ/N/vOPCmfH4BWMFCy\n" +
"wrSNezSXuDDnYXIIjO0N6NP/JsxW53ApQa53EASM5yU5JDtdWk93indQzL4TqmQn\n" +
"xVGK40UOJthMP47deEVOPaXoupX8pwHZ9ZXV9Sp/FrHa+lzB7hyVMlsldSAkLeZi\n" +
"ZRe/VTrPSGWIPPZYyFs7J5rV+zfXNi8gzKTbAkUmXv4RtdvwGBhxC3UUThzXh+4W\n" +
"eKdwBbRKj7EFnkO2JONriWYMTQ4AjaGEuyVJDusbBa3bMgpIUu2xZ/vwI/XCKAm9\n" +
"ZxRWFrMEIwIhAKKOukP5SGJ0YUs9kIIvMELbf0+s/s9ptJW6tZceHmJj\n" +
"-----END PRIVATE KEY-----\n"
// DsaPublicKeyPEM was generated from above with:
// openssl dsa -in dsa.privkey.pem -pubout -out dsa.pubkey.pem
DsaPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" +
"MIIDRzCCAjoGByqGSM44BAEwggItAoIBAQDdDvapBzRkzZ5SO9n9c5E5BNuGaPO5\n" +
"l3NjuR37zafng096pXP4VaaTbog13ulQ1uf9OOeI3n6kLakr6n1qUUsTX1s6+xjj\n" +
"HtSDCul32xAh5rdbhDsf09oRb4GigXNP994L1OadTTKfCg2FkHfcKveTc8W3/r2W\n" +
"bKuR33XBOleuy2tC6tSHhtovmXq3b8lPdPGkrHrF7X2FaqoWwEu7+P6QTajYDDVN\n" +
"UseDj/vhMkt+oCRacIi71AvS4ZCdbzSRF8mdP61QletcymDUfErsKwMRbnGwBYXf\n" +
"vQizRQ9o/uNGu7oWJI05txWFKoIiz5AkhaJ71xG3CeLCGiLjPoB8Z4RhAiEA6RLM\n" +
"CxaNrV/AHjzr8sJb7O8MkqIIYtNqWKZ9rDMdAcUCggEBAMm8K6MRn9Z5AUuU//TN\n" +
"L7YOOp1rGcqPXG5d+gss6hy8zDTp2etA2YO7+cFCJhJ/N/vOPCmfH4BWMFCywrSN\n" +
"ezSXuDDnYXIIjO0N6NP/JsxW53ApQa53EASM5yU5JDtdWk93indQzL4TqmQnxVGK\n" +
"40UOJthMP47deEVOPaXoupX8pwHZ9ZXV9Sp/FrHa+lzB7hyVMlsldSAkLeZiZRe/\n" +
"VTrPSGWIPPZYyFs7J5rV+zfXNi8gzKTbAkUmXv4RtdvwGBhxC3UUThzXh+4WeKdw\n" +
"BbRKj7EFnkO2JONriWYMTQ4AjaGEuyVJDusbBa3bMgpIUu2xZ/vwI/XCKAm9ZxRW\n" +
"FrMDggEFAAKCAQBQIcYLTmlfBhScbOgN07VxJpq6t4uf8N//Je7JFmpnB73MK78N\n" +
"+4OSkGPjfvOSWbMxz45lMxKv6DTi4xes6u/qEbVmzkdzL3NoR7B4POrRPxwJASLt\n" +
"hu93PVLrJMxkjHnOBek8lih7wtuhdnL7vWgONr//KtXf0ELN/i67QERochQqpwVT\n" +
"UmZmY+Z4EdJCxlH7Py0JJaRhXlXIlyue0cR0j6NeZZyoh1vZArXu7RhIPRG3q/KW\n" +
"jM+u3UA7o9ckZEuR+yV6kWYyD1KyAlhhpNb5bkLLqMiPzbvP7S+yJtuMWR+lxwZu\n" +
"Bfmoo5fV5QCYil35AiyGsWEnXOD16rk8LUSy\n" +
"-----END PUBLIC KEY-----\n"
// DsaSignedAbcdHex was generated with:
// echo -n "abcd" > sign.input
// openssl dgst -dss1 -sign dsa.privkey.pem -out sign.dsa sign.input
// Note that this includes randomization so will give different results each time.
// Verify with:
// openssl dgst -dss1 -verify dsa.pubkey.pem -signature sign.dsa sign.input
DsaSignedAbcdHex = "3045022100c287211dec54eab597ed5264f6fdf57faf651909914c533d42f0e3" +
"2809e9141402205f34cc4b8ca12ebdf025bf36bbe1ff7d807d4cfe951ac1329a" +
"35a39f5e971f10"
// EcdsaPrivateKeyPEM was generated with:
// openssl ecparam -genkey -name prime256v1 -noout -out ecdsa.privkey.pem
EcdsaPrivateKeyPEM = "-----BEGIN EC PRIVATE KEY-----\n" +
"MHcCAQEEIHg0hg3vLqLVI7wv2y0cCk+kmwuwoKsMZqzqbjqP1AtjoAoGCCqGSM49\n" +
"AwEHoUQDQgAEjHs6Rw7KFt8Wd2ZcioZi7eZY5nodUXMnCWUhZzsGVsPaexqUyPSr\n" +
"9cQgrCe7MPRLJ524AO6rREqfs7FKt85++A==\n" +
"-----END EC PRIVATE KEY-----\n"
// EcdsaPrivateKeyPKCS8PEM is a copy of the private key above, encoded in PKCS#8 format.
// Generated from above with:
// openssl pkcs8 -topk8 -nocrypt -in ecdsa.privkey.pem -out ecdsa.privkey.pkcs8.pem
EcdsaPrivateKeyPKCS8PEM = "-----BEGIN PRIVATE KEY-----\n" +
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgeDSGDe8uotUjvC/b\n" +
"LRwKT6SbC7CgqwxmrOpuOo/UC2OhRANCAASMezpHDsoW3xZ3ZlyKhmLt5ljmeh1R\n" +
"cycJZSFnOwZWw9p7GpTI9Kv1xCCsJ7sw9EsnnbgA7qtESp+zsUq3zn74\n" +
"-----END PRIVATE KEY-----\n"
// EcdsaPublicKeyPEM was generated from above with:
// openssl ec -in ecdsa.privkey.pem -pubout -out ecdsa.pubkey.pem
EcdsaPublicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" +
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjHs6Rw7KFt8Wd2ZcioZi7eZY5nod\n" +
"UXMnCWUhZzsGVsPaexqUyPSr9cQgrCe7MPRLJ524AO6rREqfs7FKt85++A==\n" +
"-----END PUBLIC KEY-----\n"
// EcdsaSignedAbcdHex was generated with:
// echo -n "abcd" > sign.input
// openssl dgst -sha256 -sign ecdsa.privkey.pem -out sign.ecdsa sign.input
// Note that this includes randomization so will give different results each time.
// Verify with:
// openssl dgst -sha256 -verify ecdsa.pubkey.pem -signature sign.ecdsa sign.input
EcdsaSignedAbcdHex = "304502202e0204dadf2baa35e426b66ab8cd32a9ba33421187645a9110512e3e" +
"d1b8007b022100ae83f5f993ab3af6f46bb09b4f15d07cc582b03e1353879ada" +
"ce68796fe537e5"
)
// FromHex decodes a hex string to a byte array, and panics on error; only suitable for
// use in test code.
func FromHex(hexdata string) []byte {
data, err := hex.DecodeString(hexdata)
if err != nil {
panic("non hex data: " + err.Error())
}
return data
}

View File

@ -1,60 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 6 (0x6)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen
Validity
Not Before: Jun 1 00:00:00 2012 GMT
Not After : Jun 1 00:00:00 2022 GMT
Subject: C=GB, O=Certificate Transparency, ST=Wales, L=Erw Wen
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:b1:fa:37:93:61:11:f8:79:2d:a2:08:1c:3f:e4:
19:25:00:85:31:dc:7f:2c:65:7b:d9:e1:de:47:04:
16:0b:4c:9f:19:d5:4a:da:44:70:40:4c:1c:51:34:
1b:8f:1f:75:38:dd:dd:28:d9:ac:a4:83:69:fc:56:
46:dd:cc:76:17:f8:16:8a:ae:5b:41:d4:33:31:fc:
a2:da:df:c8:04:d5:72:08:94:90:61:f9:ee:f9:02:
ca:47:ce:88:c6:44:e0:00:f0:6e:ee:cc:ab:dc:9d:
d2:f6:8a:22:cc:b0:9d:c7:6e:0d:bc:73:52:77:65:
b1:a3:7a:8c:67:62:53:dc:c1
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
6A:0D:98:2A:3B:62:C4:4B:6D:2E:F4:E9:BB:7A:01:AA:9C:B7:98:E2
X509v3 Authority Key Identifier:
keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55
DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen
serial:00
X509v3 Basic Constraints:
CA:FALSE
Signature Algorithm: sha1WithRSAEncryption
17:1c:d8:4a:ac:41:4a:9a:03:0f:22:aa:c8:f6:88:b0:81:b2:
70:9b:84:8b:4e:55:11:40:6c:d7:07:fe:d0:28:59:7a:9f:ae:
fc:2e:ee:29:78:d6:33:aa:ac:14:ed:32:35:19:7d:a8:7e:0f:
71:b8:87:5f:1a:c9:e7:8b:28:17:49:dd:ed:d0:07:e3:ec:f5:
06:45:f8:cb:f6:67:25:6c:d6:a1:64:7b:5e:13:20:3b:b8:58:
2d:e7:d6:69:6f:65:6d:1c:60:b9:5f:45:6b:7f:cf:33:85:71:
90:8f:1c:69:72:7d:24:c4:fc:cd:24:92:95:79:58:14:d1:da:
c0:e6
-----BEGIN CERTIFICATE-----
MIICyjCCAjOgAwIBAgIBBjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk
MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX
YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw
MDAwMDBaMFIxCzAJBgNVBAYTAkdCMSEwHwYDVQQKExhDZXJ0aWZpY2F0ZSBUcmFu
c3BhcmVuY3kxDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGfMA0G
CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx+jeTYRH4eS2iCBw/5BklAIUx3H8sZXvZ
4d5HBBYLTJ8Z1UraRHBATBxRNBuPH3U43d0o2aykg2n8VkbdzHYX+BaKrltB1DMx
/KLa38gE1XIIlJBh+e75AspHzojGROAA8G7uzKvcndL2iiLMsJ3Hbg28c1J3ZbGj
eoxnYlPcwQIDAQABo4GsMIGpMB0GA1UdDgQWBBRqDZgqO2LES20u9Om7egGqnLeY
4jB9BgNVHSMEdjB0gBRfnYgNyHPmVNT4DdjmsMEktEfDVaFZpFcwVTELMAkGA1UE
BhMCR0IxJDAiBgNVBAoTG0NlcnRpZmljYXRlIFRyYW5zcGFyZW5jeSBDQTEOMAwG
A1UECBMFV2FsZXMxEDAOBgNVBAcTB0VydyBXZW6CAQAwCQYDVR0TBAIwADANBgkq
hkiG9w0BAQUFAAOBgQAXHNhKrEFKmgMPIqrI9oiwgbJwm4SLTlURQGzXB/7QKFl6
n678Lu4peNYzqqwU7TI1GX2ofg9xuIdfGsnniygXSd3t0Afj7PUGRfjL9mclbNah
ZHteEyA7uFgt59Zpb2VtHGC5X0Vrf88zhXGQjxxpcn0kxPzNJJKVeVgU0drA5g==
-----END CERTIFICATE-----

View File

@ -1,65 +0,0 @@
// 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 tls
import (
"encoding/hex"
"strings"
"testing"
"github.com/google/certificate-transparency-go/testdata"
)
func TestGenerateHash(t *testing.T) {
var tests = []struct {
in string // hex encoded
algo HashAlgorithm
want string // hex encoded
errstr string
}{
// Empty hash values
{"", MD5, "d41d8cd98f00b204e9800998ecf8427e", ""},
{"", SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
{"", SHA224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""},
{"", SHA256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
{"", SHA384, "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
{"", SHA512, "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
{"", 999, "", "unsupported"},
// Hashes of "abcd".
{"61626364", MD5, testdata.AbcdMD5, ""},
{"61626364", SHA1, testdata.AbcdSHA1, ""},
{"61626364", SHA224, testdata.AbcdSHA224, ""},
{"61626364", SHA256, testdata.AbcdSHA256, ""},
{"61626364", SHA384, testdata.AbcdSHA384, ""},
{"61626364", SHA512, testdata.AbcdSHA512, ""},
}
for _, test := range tests {
got, _, err := generateHash(test.algo, testdata.FromHex(test.in))
if test.errstr != "" {
if err == nil {
t.Errorf("generateHash(%s)=%s,nil; want error %q", test.in, hex.EncodeToString(got), test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("generateHash(%s)=nil,%q; want error %q", test.in, test.errstr, err.Error())
}
continue
}
if err != nil {
t.Errorf("generateHash(%s)=nil,%q; want %s", test.in, err, test.want)
} else if hex.EncodeToString(got) != test.want {
t.Errorf("generateHash(%s)=%s,nil; want %s", test.in, hex.EncodeToString(got), test.want)
}
}
}

View File

@ -1,160 +0,0 @@
// 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 tls_test
import (
"crypto"
"encoding/pem"
mathrand "math/rand"
"reflect"
"strings"
"testing"
"time"
"github.com/google/certificate-transparency-go/testdata"
"github.com/google/certificate-transparency-go/tls"
"github.com/google/certificate-transparency-go/x509"
)
func TestVerifySignature(t *testing.T) {
var tests = []struct {
pubKey crypto.PublicKey
in string // hex encoded
hashAlgo tls.HashAlgorithm
sigAlgo tls.SignatureAlgorithm
errstr string
sig string // hex encoded
}{
{PEM2PK(testdata.RsaPublicKeyPEM), "61626364", 99, tls.ECDSA, "unsupported Algorithm.Hash", "1234"},
{PEM2PK(testdata.RsaPublicKeyPEM), "61626364", tls.SHA256, 99, "unsupported Algorithm.Signature", "1234"},
{PEM2PK(testdata.RsaPublicKeyPEM), "61626364", tls.SHA256, tls.DSA, "cannot verify DSA", "1234"},
{PEM2PK(testdata.RsaPublicKeyPEM), "61626364", tls.SHA256, tls.ECDSA, "cannot verify ECDSA", "1234"},
{PEM2PK(testdata.RsaPublicKeyPEM), "61626364", tls.SHA256, tls.RSA, "verification error", "1234"},
{PEM2PK(testdata.RsaPublicKeyPEM), "61626364", tls.SHA256, tls.ECDSA, "cannot verify ECDSA", "1234"},
{PEM2PK(testdata.DsaPublicKeyPEM), "61626364", tls.SHA1, tls.RSA, "cannot verify RSA", "1234"},
{PEM2PK(testdata.DsaPublicKeyPEM), "61626364", tls.SHA1, tls.ECDSA, "cannot verify ECDSA", "1234"},
{PEM2PK(testdata.DsaPublicKeyPEM), "61626364", tls.SHA1, tls.DSA, "failed to unmarshal DSA signature", "1234"},
{PEM2PK(testdata.DsaPublicKeyPEM), "61626364", tls.SHA1, tls.DSA, "failed to verify DSA signature", "3006020101020101eeff"},
{PEM2PK(testdata.DsaPublicKeyPEM), "61626364", tls.SHA1, tls.DSA, "zero or negative values", "3006020100020181"},
{PEM2PK(testdata.EcdsaPublicKeyPEM), "61626364", tls.SHA256, tls.RSA, "cannot verify RSA", "1234"},
{PEM2PK(testdata.EcdsaPublicKeyPEM), "61626364", tls.SHA256, tls.DSA, "cannot verify DSA", "1234"},
{PEM2PK(testdata.EcdsaPublicKeyPEM), "61626364", tls.SHA256, tls.ECDSA, "failed to unmarshal ECDSA signature", "1234"},
{PEM2PK(testdata.EcdsaPublicKeyPEM), "61626364", tls.SHA256, tls.ECDSA, "failed to verify ECDSA signature", "3006020101020101eeff"},
{PEM2PK(testdata.EcdsaPublicKeyPEM), "61626364", tls.SHA256, tls.ECDSA, "zero or negative values", "3006020100020181"},
{PEM2PK(testdata.RsaPublicKeyPEM), "61626364", tls.SHA256, tls.RSA, "", testdata.RsaSignedAbcdHex},
{PEM2PK(testdata.DsaPublicKeyPEM), "61626364", tls.SHA1, tls.DSA, "", testdata.DsaSignedAbcdHex},
{PEM2PK(testdata.EcdsaPublicKeyPEM), "61626364", tls.SHA256, tls.ECDSA, "", testdata.EcdsaSignedAbcdHex},
}
for _, test := range tests {
algo := tls.SignatureAndHashAlgorithm{Hash: test.hashAlgo, Signature: test.sigAlgo}
signed := tls.DigitallySigned{Algorithm: algo, Signature: testdata.FromHex(test.sig)}
err := tls.VerifySignature(test.pubKey, testdata.FromHex(test.in), signed)
if test.errstr != "" {
if err == nil {
t.Errorf("VerifySignature(%s)=nil; want %q", test.in, test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("VerifySignature(%s)=%q; want %q", test.in, err.Error(), test.errstr)
}
continue
}
if err != nil {
t.Errorf("VerifySignature(%s)=%q; want nil", test.in, err)
}
}
}
func TestCreateSignatureVerifySignatureRoundTrip(t *testing.T) {
var tests = []struct {
privKey crypto.PrivateKey
pubKey crypto.PublicKey
hashAlgo tls.HashAlgorithm
}{
{PEM2PrivKey(testdata.RsaPrivateKeyPEM), PEM2PK(testdata.RsaPublicKeyPEM), tls.SHA256},
{PEM2PrivKey(testdata.EcdsaPrivateKeyPKCS8PEM), PEM2PK(testdata.EcdsaPublicKeyPEM), tls.SHA256},
}
seed := time.Now().UnixNano()
r := mathrand.New(mathrand.NewSource(seed))
for _, test := range tests {
for j := 0; j < 1; j++ {
dataLen := 10 + r.Intn(100)
data := make([]byte, dataLen)
_, _ = r.Read(data)
sig, err := tls.CreateSignature(test.privKey, test.hashAlgo, data)
if err != nil {
t.Errorf("CreateSignature(%T, %v) failed with: %q", test.privKey, test.hashAlgo, err.Error())
continue
}
if err := tls.VerifySignature(test.pubKey, data, sig); err != nil {
t.Errorf("VerifySignature(%T, %v) failed with: %q", test.pubKey, test.hashAlgo, err)
}
}
}
}
func TestCreateSignatureFailures(t *testing.T) {
var tests = []struct {
privKey crypto.PrivateKey
hashAlgo tls.HashAlgorithm
in string // hex encoded
errstr string
}{
{PEM2PrivKey(testdata.EcdsaPrivateKeyPKCS8PEM), 99, "abcd", "unsupported Algorithm.Hash"},
{nil, tls.SHA256, "abcd", "unsupported private key type"},
}
for _, test := range tests {
if sig, err := tls.CreateSignature(test.privKey, test.hashAlgo, testdata.FromHex(test.in)); err == nil {
t.Errorf("CreateSignature(%T, %v)=%v,nil; want error %q", test.privKey, test.hashAlgo, sig, test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("CreateSignature(%T, %v)=nil,%q; want error %q", test.privKey, test.hashAlgo, err.Error(), test.errstr)
}
}
}
func PEM2PK(s string) crypto.PublicKey {
p, _ := pem.Decode([]byte(s))
if p == nil {
panic("no PEM block found in " + s)
}
pubKey, _ := x509.ParsePKIXPublicKey(p.Bytes)
if pubKey == nil {
panic("public key not parsed from " + s)
}
return pubKey
}
func PEM2PrivKey(s string) crypto.PrivateKey {
p, _ := pem.Decode([]byte(s))
if p == nil {
panic("no PEM block found in " + s)
}
// Try various different private key formats one after another.
if rsaPrivKey, err := x509.ParsePKCS1PrivateKey(p.Bytes); err == nil {
return *rsaPrivKey
}
if pkcs8Key, err := x509.ParsePKCS8PrivateKey(p.Bytes); err == nil {
if reflect.TypeOf(pkcs8Key).Kind() == reflect.Ptr {
pkcs8Key = reflect.ValueOf(pkcs8Key).Elem().Interface()
}
return pkcs8Key
}
return nil
}

View File

@ -1,355 +0,0 @@
// 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 tls
import (
"bytes"
"encoding/hex"
"reflect"
"strings"
"testing"
)
type testStruct struct {
Data []byte `tls:"minlen:2,maxlen:4"`
IntVal uint16
Other [4]byte
Enum Enum `tls:"size:2"`
}
type testVariant struct {
Which Enum `tls:"size:1"`
Val16 *uint16 `tls:"selector:Which,val:0"`
Val32 *uint32 `tls:"selector:Which,val:1"`
}
type testTwoVariants struct {
Which Enum `tls:"size:1"`
Val16 *uint16 `tls:"selector:Which,val:0"`
Val32 *uint32 `tls:"selector:Which,val:1"`
Second Enum `tls:"size:1"`
Second16 *uint16 `tls:"selector:Second,val:0"`
Second32 *uint32 `tls:"selector:Second,val:1"`
}
// Check that library users can define their own Enum types.
type aliasEnum Enum
type testAliasEnum struct {
Val aliasEnum `tls:"size:1"`
Val16 *uint16 `tls:"selector:Val,val:1"`
Val32 *uint32 `tls:"selector:Val,val:2"`
}
type testNonByteSlice struct {
Vals []uint16 `tls:"minlen:2,maxlen:6"`
}
type testSliceOfStructs struct {
Vals []testVariant `tls:"minlen:0,maxlen:100"`
}
type testInnerType struct {
Val []byte `tls:"minlen:0,maxlen:65535"`
}
type testSliceOfSlices struct {
Inners []testInnerType `tls:"minlen:0,maxlen:65535"`
}
func TestMarshalUnmarshalRoundTrip(t *testing.T) {
thing := testStruct{Data: []byte{0x01, 0x02, 0x03}, IntVal: 42, Other: [4]byte{1, 2, 3, 4}, Enum: 17}
data, err := Marshal(thing)
if err != nil {
t.Fatalf("Failed to Marshal(%+v): %s", thing, err.Error())
}
var other testStruct
rest, err := Unmarshal(data, &other)
if err != nil {
t.Fatalf("Failed to Unmarshal(%s)", hex.EncodeToString(data))
}
if len(rest) > 0 {
t.Errorf("Data left over after Unmarshal(%s): %s", hex.EncodeToString(data), hex.EncodeToString(rest))
}
}
func TestFieldTagToFieldInfo(t *testing.T) {
var tests = []struct {
tag string
want *fieldInfo
errstr string
}{
{"", nil, ""},
{"bogus", nil, ""},
{"also,bogus", nil, ""},
{"also,bogus:99", nil, ""},
{"maxval:1xyz", nil, ""},
{"maxval:1", &fieldInfo{count: 1, countSet: true}, ""},
{"maxval:255", &fieldInfo{count: 1, countSet: true}, ""},
{"maxval:256", &fieldInfo{count: 2, countSet: true}, ""},
{"maxval:65535", &fieldInfo{count: 2, countSet: true}, ""},
{"maxval:65536", &fieldInfo{count: 3, countSet: true}, ""},
{"maxval:16777215", &fieldInfo{count: 3, countSet: true}, ""},
{"maxval:16777216", &fieldInfo{count: 4, countSet: true}, ""},
{"maxval:16777216", &fieldInfo{count: 4, countSet: true}, ""},
{"maxval:4294967295", &fieldInfo{count: 4, countSet: true}, ""},
{"maxval:4294967296", &fieldInfo{count: 5, countSet: true}, ""},
{"maxval:1099511627775", &fieldInfo{count: 5, countSet: true}, ""},
{"maxval:1099511627776", &fieldInfo{count: 6, countSet: true}, ""},
{"maxval:281474976710655", &fieldInfo{count: 6, countSet: true}, ""},
{"maxval:281474976710656", &fieldInfo{count: 7, countSet: true}, ""},
{"maxval:72057594037927935", &fieldInfo{count: 7, countSet: true}, ""},
{"maxval:72057594037927936", &fieldInfo{count: 8, countSet: true}, ""},
{"minlen:1x", nil, ""},
{"maxlen:1x", nil, ""},
{"maxlen:1", &fieldInfo{count: 1, countSet: true, maxlen: 1}, ""},
{"maxlen:255", &fieldInfo{count: 1, countSet: true, maxlen: 255}, ""},
{"maxlen:65535", &fieldInfo{count: 2, countSet: true, maxlen: 65535}, ""},
{"minlen:65530,maxlen:65535", &fieldInfo{count: 2, countSet: true, minlen: 65530, maxlen: 65535}, ""},
{"maxlen:65535,minlen:65530", &fieldInfo{count: 2, countSet: true, minlen: 65530, maxlen: 65535}, ""},
{"minlen:65536,maxlen:65535", nil, "inverted"},
{"maxlen:16777215", &fieldInfo{count: 3, countSet: true, maxlen: 16777215}, ""},
{"maxlen:281474976710655", &fieldInfo{count: 6, countSet: true, maxlen: 281474976710655}, ""},
{"maxlen:72057594037927936", &fieldInfo{count: 8, countSet: true, maxlen: 72057594037927936}, ""},
{"size:0", nil, "unknown size"},
{"size:1", &fieldInfo{count: 1, countSet: true}, ""},
{"size:2", &fieldInfo{count: 2, countSet: true}, ""},
{"size:3", &fieldInfo{count: 3, countSet: true}, ""},
{"size:4", &fieldInfo{count: 4, countSet: true}, ""},
{"size:5", &fieldInfo{count: 5, countSet: true}, ""},
{"size:6", &fieldInfo{count: 6, countSet: true}, ""},
{"size:7", &fieldInfo{count: 7, countSet: true}, ""},
{"size:8", &fieldInfo{count: 8, countSet: true}, ""},
{"size:9", nil, "too large"},
{"size:1x", nil, ""},
{"size:1,val:9", nil, "selector value"},
{"selector:Bob,val:x9", &fieldInfo{selector: "Bob"}, ""},
{"selector:Fred,val:1", &fieldInfo{selector: "Fred", val: 1}, ""},
{"val:9,selector:Fred,val:1", &fieldInfo{selector: "Fred", val: 1}, ""},
}
for _, test := range tests {
got, err := fieldTagToFieldInfo(test.tag, "")
if test.errstr != "" {
if err == nil {
t.Errorf("fieldTagToFieldInfo('%v')=%+v,nil; want error %q", test.tag, got, test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("fieldTagToFieldInfo('%v')=nil,%q; want error %q", test.tag, err.Error(), test.errstr)
}
continue
}
if err != nil {
t.Errorf("fieldTagToFieldInfo('%v')=nil,%q; want %+v", test.tag, err.Error(), test.want)
} else if !reflect.DeepEqual(got, test.want) {
t.Errorf("fieldTagToFieldInfo('%v')=%+v,nil; want %+v", test.tag, got, test.want)
}
}
}
// Can't take the address of a numeric constant so use helper functions
func newByte(n byte) *byte { return &n }
func newUint8(n uint8) *uint8 { return &n }
func newUint16(n uint16) *uint16 { return &n }
func newUint24(n Uint24) *Uint24 { return &n }
func newUint32(n uint32) *uint32 { return &n }
func newUint64(n uint64) *uint64 { return &n }
func newInt16(n int16) *int16 { return &n }
func newEnum(n Enum) *Enum { return &n }
func TestUnmarshalMarshalWithParamsRoundTrip(t *testing.T) {
var tests = []struct {
data string // hex encoded
params string
item interface{}
}{
{"00", "", newUint8(0)},
{"03", "", newByte(3)},
{"0101", "", newUint16(0x0101)},
{"010203", "", newUint24(0x010203)},
{"000000", "", newUint24(0x00)},
{"00000009", "", newUint32(0x09)},
{"0000000901020304", "", newUint64(0x0901020304)},
{"030405", "", &[3]byte{3, 4, 5}},
{"03", "", &[1]byte{3}},
{"0001", "size:2", newEnum(1)},
{"0100000001", "size:5", newEnum(0x100000001)},
{"12", "maxval:18", newEnum(18)},
// Note that maxval is just used to give enum size; it's not policed
{"20", "maxval:18", newEnum(32)},
{"020a0b", "minlen:1,maxlen:5", &[]byte{0xa, 0xb}},
{"020a0b0101010203040011", "", &testStruct{Data: []byte{0xa, 0xb}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}},
{"000102", "", &testVariant{Which: 0, Val16: newUint16(0x0102)}},
{"0101020304", "", &testVariant{Which: 1, Val32: newUint32(0x01020304)}},
{"0001020104030201", "", &testTwoVariants{Which: 0, Val16: newUint16(0x0102), Second: 1, Second32: newUint32(0x04030201)}},
{"06010102020303", "", &testNonByteSlice{Vals: []uint16{0x101, 0x202, 0x303}}},
{"00", "", &testSliceOfStructs{Vals: []testVariant{}}},
{"080001020101020304", "",
&testSliceOfStructs{
Vals: []testVariant{
{Which: 0, Val16: newUint16(0x0102)},
{Which: 1, Val32: newUint32(0x01020304)},
},
},
},
{"000a00030102030003040506", "",
&testSliceOfSlices{
Inners: []testInnerType{
{Val: []byte{1, 2, 3}},
{Val: []byte{4, 5, 6}},
},
},
},
{"011011", "", &testAliasEnum{Val: 1, Val16: newUint16(0x1011)}},
{"0403", "", &SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA}},
{"04030003010203", "",
&DigitallySigned{
Algorithm: SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA},
Signature: []byte{1, 2, 3},
},
},
}
for _, test := range tests {
inVal := reflect.ValueOf(test.item).Elem()
pv := reflect.New(reflect.TypeOf(test.item).Elem())
val := pv.Interface()
inData, _ := hex.DecodeString(test.data)
if _, err := UnmarshalWithParams(inData, val, test.params); err != nil {
t.Errorf("Unmarshal(%s)=nil,%q; want %+v", test.data, err.Error(), inVal)
} else if !reflect.DeepEqual(val, test.item) {
t.Errorf("Unmarshal(%s)=%+v,nil; want %+v", test.data, reflect.ValueOf(val).Elem(), inVal)
}
if data, err := MarshalWithParams(inVal.Interface(), test.params); err != nil {
t.Errorf("Marshal(%+v)=nil,%q; want %s", inVal, err.Error(), test.data)
} else if !bytes.Equal(data, inData) {
t.Errorf("Marshal(%+v)=%s,nil; want %s", inVal, hex.EncodeToString(data), test.data)
}
}
}
type testInvalidFieldTag struct {
Data []byte `tls:"minlen:3,maxlen:2"`
}
type testDuplicateSelectorVal struct {
Which Enum `tls:"size:1"`
Val *uint16 `tls:"selector:Which,val:0"`
DupVal *uint32 `tls:"selector:Which"` // implicit val:0
}
type testMissingSelector struct {
Val *uint16 `tls:"selector:Missing,val:0"`
}
type testChoiceNotPointer struct {
Which Enum `tls:"size:1"`
Val uint16 `tls:"selector:Which,val:0"`
}
type nonEnumAlias uint16
func newNonEnumAlias(n nonEnumAlias) *nonEnumAlias { return &n }
func TestUnmarshalWithParamsFailures(t *testing.T) {
var tests = []struct {
data string // hex encoded
params string
item interface{}
errstr string
}{
{"", "", newUint8(0), "truncated"},
{"0x01", "", newUint16(0x0101), "truncated"},
{"0103", "", newUint24(0x010203), "truncated"},
{"00", "", newUint24(0x00), "truncated"},
{"000009", "", newUint32(0x09), "truncated"},
{"00000901020304", "", newUint64(0x0901020304), "truncated"},
{"0102", "", newInt16(0x0102), "unsupported type"}, // TLS encoding only supports unsigned integers
{"0607", "", &[3]byte{6, 7, 8}, "truncated array"},
{"01010202", "", &[3]uint16{0x101, 0x202}, "unsupported array"},
{"01", "", newEnum(1), "no field size"},
{"00", "size:2", newEnum(0), "truncated"},
{"00", "size:9", newEnum(0), "too large"},
{"020a0b", "minlen:4,maxlen:8", &[]byte{0x0a, 0x0b}, "too small"},
{"040a0b0c0d", "minlen:1,maxlen:3", &[]byte{0x0a, 0x0b, 0x0c, 0x0d}, "too large"},
{"020a0b", "minlen:8,maxlen:6", &[]byte{0x0a, 0x0b}, "inverted"},
{"020a", "minlen:0,maxlen:6", &[]byte{0x0a, 0x0b}, "truncated"},
{"02", "minlen:0,maxlen:6", &[]byte{0x0a, 0x0b}, "truncated"},
{"0001", "minlen:0,maxlen:256", &[]byte{0x0a, 0x0b}, "truncated"},
{"020a", "minlen:0", &[]byte{0x0a, 0x0b}, "unknown size"},
{"020a", "", &[]byte{0x0a, 0x0b}, "no field size information"},
{"020a0b", "", &testInvalidFieldTag{}, "range inverted"},
{"020a0b01010102030400", "",
&testStruct{Data: []byte{0xa, 0xb}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}, "truncated"},
{"010102", "", &testVariant{Which: 1, Val32: newUint32(0x01020304)}, "truncated"},
{"092122", "", &testVariant{Which: 0, Val16: newUint16(0x2122)}, "unhandled value for selector"},
{"0001020304", "", &testDuplicateSelectorVal{Which: 0, Val: newUint16(0x0102)}, "duplicate selector value"},
{"0102", "", &testMissingSelector{Val: newUint16(1)}, "selector not seen"},
{"000007", "", &testChoiceNotPointer{Which: 0, Val: 7}, "choice field not a pointer type"},
{"05010102020303", "", &testNonByteSlice{Vals: []uint16{0x101, 0x202, 0x303}}, "truncated"},
{"0101", "size:2", newNonEnumAlias(0x0102), "unsupported type"},
{"0403010203", "",
&DigitallySigned{
Algorithm: SignatureAndHashAlgorithm{Hash: SHA256, Signature: ECDSA},
Signature: []byte{1, 2, 3}}, "truncated"},
}
for _, test := range tests {
pv := reflect.New(reflect.TypeOf(test.item).Elem())
val := pv.Interface()
in, _ := hex.DecodeString(test.data)
if _, err := UnmarshalWithParams(in, val, test.params); err == nil {
t.Errorf("Unmarshal(%s)=%+v,nil; want error %q", test.data, reflect.ValueOf(val).Elem(), test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("Unmarshal(%s)=nil,%q; want error %q", test.data, err.Error(), test.errstr)
}
}
}
func TestMarshalWithParamsFailures(t *testing.T) {
var tests = []struct {
item interface{}
params string
errstr string
}{
{Uint24(0x1000000), "", "overflow"},
{int16(0x0102), "", "unsupported type"}, // All TLS ints are unsigned
{Enum(1), "", "field tag missing"},
{Enum(256), "size:1", "too large"},
{Enum(256), "maxval:255", "too large"},
{Enum(2), "", "field tag missing"},
{Enum(256), "size:9", "too large"},
{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:1,maxlen:3", "too large"},
{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6,maxlen:13", "too small"},
{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6,maxlen:3", "inverted"},
{[]byte{0xa, 0xb, 0xc, 0xd}, "minlen:6", "unknown size"},
{[]byte{0xa, 0xb, 0xc, 0xd}, "", "field tag missing"},
{[3]uint16{0x101, 0x202}, "", "unsupported array"},
{testInvalidFieldTag{}, "", "inverted"},
{testStruct{Data: []byte{0xa}, IntVal: 0x101, Other: [4]byte{1, 2, 3, 4}, Enum: 17}, "", "too small"},
{testVariant{Which: 0, Val32: newUint32(0x01020304)}, "", "chosen field is nil"},
{testVariant{Which: 0, Val16: newUint16(11), Val32: newUint32(0x01020304)}, "", "unchosen field is non-nil"},
{testVariant{Which: 3}, "", "unhandled value for selector"},
{testMissingSelector{Val: newUint16(1)}, "", "selector not seen"},
{testChoiceNotPointer{Which: 0, Val: 7}, "", "choice field not a pointer"},
{testDuplicateSelectorVal{Which: 0, Val: newUint16(1)}, "", "duplicate selector value"},
{testNonByteSlice{Vals: []uint16{1, 2, 3, 4}}, "", "too large"},
{testSliceOfStructs{[]testVariant{{Which: 3}}}, "", "unhandled value for selector"},
{nonEnumAlias(0x0102), "", "unsupported type"},
}
for _, test := range tests {
if data, err := MarshalWithParams(test.item, test.params); err == nil {
t.Errorf("Marshal(%+v)=%x,nil; want error %q", test.item, data, test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("Marshal(%+v)=nil,%q; want error %q", test.item, err.Error(), test.errstr)
}
}
}

View File

@ -1,100 +0,0 @@
// 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 tls
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"testing"
)
func TestHashAlgorithmString(t *testing.T) {
var tests = []struct {
algo HashAlgorithm
want string
}{
{None, "None"},
{MD5, "MD5"},
{SHA1, "SHA1"},
{SHA224, "SHA224"},
{SHA256, "SHA256"},
{SHA384, "SHA384"},
{SHA512, "SHA512"},
{99, "UNKNOWN(99)"},
}
for _, test := range tests {
if got := test.algo.String(); got != test.want {
t.Errorf("%v.String()=%q; want %q", test.algo, got, test.want)
}
}
}
func TestSignatureAlgorithmString(t *testing.T) {
var tests = []struct {
algo SignatureAlgorithm
want string
}{
{Anonymous, "Anonymous"},
{RSA, "RSA"},
{DSA, "DSA"},
{ECDSA, "ECDSA"},
{99, "UNKNOWN(99)"},
}
for _, test := range tests {
if got := test.algo.String(); got != test.want {
t.Errorf("%v.String()=%q; want %q", test.algo, got, test.want)
}
}
}
func TestDigitallySignedString(t *testing.T) {
var tests = []struct {
ds DigitallySigned
want string
}{
{
ds: DigitallySigned{Algorithm: SignatureAndHashAlgorithm{Hash: SHA1, Signature: RSA}, Signature: []byte{0x01, 0x02}},
want: "Signature: HashAlgo=SHA1 SignAlgo=RSA Value=0102",
},
{
ds: DigitallySigned{Algorithm: SignatureAndHashAlgorithm{Hash: 99, Signature: 99}, Signature: []byte{0x03, 0x04}},
want: "Signature: HashAlgo=UNKNOWN(99) SignAlgo=UNKNOWN(99) Value=0304",
},
}
for _, test := range tests {
if got := test.ds.String(); got != test.want {
t.Errorf("%v.String()=%q; want %q", test.ds, got, test.want)
}
}
}
func TestSignatureAlgorithm(t *testing.T) {
for _, test := range []struct {
name string
key crypto.PublicKey
want SignatureAlgorithm
}{
{name: "ECDSA", key: new(ecdsa.PublicKey), want: ECDSA},
{name: "RSA", key: new(rsa.PublicKey), want: RSA},
{name: "DSA", key: new(dsa.PublicKey), want: DSA},
{name: "Other", key: "foo", want: Anonymous},
} {
if got := SignatureAlgorithmFromPubKey(test.key); got != test.want {
t.Errorf("%v: SignatureAlgorithm() = %v, want %v", test.name, got, test.want)
}
}
}

View File

@ -1,131 +0,0 @@
// Copyright 2015 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 ct
import (
"encoding/hex"
"strings"
"testing"
"github.com/google/certificate-transparency-go/tls"
)
const (
CertEntry = "000000000149a6e03abe00000006513082064d30820535a003020102020c6a5d4161f5c9b68043270b0c300d06092a864886f70d0101050500305e310b300906035504061302424531193017060355040a1310476c6f62616c5369676e206e762d7361313430320603550403132b476c6f62616c5369676e20457874656e6465642056616c69646174696f6e204341202d2047322054455354301e170d3134313131333031353830315a170d3136313131333031353830315a3082011331183016060355040f0c0f427573696e65737320456e74697479311230100603550405130936363636363636363631133011060b2b0601040182373c0201031302444531293027060b2b0601040182373c02010113186576206a7572697364696374696f6e206c6f63616c69747931263024060b2b0601040182373c02010213156576206a7572697364696374696f6e207374617465310b3009060355040613024a50310a300806035504080c0153310a300806035504070c014c311530130603550409130c657620616464726573732033310c300a060355040b0c034f5531310c300a060355040b0c034f5532310a3008060355040a0c014f3117301506035504030c0e637372636e2e73736c32342e6a7030820122300d06092a864886f70d01010105000382010f003082010a02820101008db9f0d6b359466dffe95ba43dc1a5680eedc8f3cabbc573a236a109bf6e58df816c7bb8156147ab526eceaffd0576e6e1c09ea33433e114d7e5038c697298c7957f01a7e1142320847cf234995bbe42798340cb99e6a7e2cfa950277aef6e02f4d96ddceb0af9541171b0f8f1aa4f0d02453e6e654b25a13f2aff4357cae8177d3bd21855686591a2309d9ff5dead8240304e22eafcc5508587e6b6ad1d00b53c28e5b936269afbf214b73edbdc8a48a86c1c23f3dce55fcce60502c0908bca9bdb22c16c0b34d11b4fd27e9d7bcb56c5ec0fc4d52500fb06b0af5c4112e421022b78b31030cb73e9fd92ffc65919fd8f35e604fcaf025b9c77e3e5dff749a70203010001a38202523082024e300e0603551d0f0101ff0404030205a0304c0603551d2004453043304106092b06010401a03201013034303206082b06010505070201162668747470733a2f2f7777772e676c6f62616c7369676e2e636f6d2f7265706f7369746f72792f30480603551d1f0441303f303da03ba0398637687474703a2f2f63726c2e676c6f62616c7369676e2e636f6d2f67732f67736f7267616e697a6174696f6e76616c63617467322e63726c30819c06082b0601050507010104818f30818c304a06082b06010505073002863e687474703a2f2f7365637572652e676c6f62616c7369676e2e636f6d2f6361636572742f67736f7267616e697a6174696f6e76616c63617467322e637274303e06082b060105050730018632687474703a2f2f6f637370322e676c6f62616c7369676e2e636f6d2f67736f7267616e697a6174696f6e76616c6361746732301d0603551d250416301406082b0601050507030106082b0601050507030230190603551d1104123010820e637372636e2e73736c32342e6a70301d0603551d0e041604147f834b2903e35efff651619083a2efd69a6d70f4301f0603551d23041830168014ab30a406d972d0029ab2c7d3f4241be2fca5320230818a060a2b06010401d679020402047c047a0078007600b0cc83e5a5f97d6baf7c09cc284904872ac7e88b132c6350b7c6fd26e16c6c7700000149a6dc346b00000403004730450220469f4dc0553b7832bd56633c3b9d53faaec84df414b7a05ab1b2d544d146ac3e022100ee899419fd4f95544798f7883fe093692feb4c90e84d651600f7019166a43701300d06092a864886f70d010105050003820101007dcd3e228d68cdc0734c7629fd7d40cd742d0ed1d0d9f49a643af12dcdbc61394638b7c519bb7cae530ccdc3a5037d5cdd8a4d2c01abdc834daf1993f7a22ee2c223377a94da4e68ac69a0b50d2d473ec77651e001c5f71a23cc2defe7616fd6c6491aa7f9a2bb16b930ce3f8cc37cf6a47bfb04fd4eff7db8433cc6fdb05146a4a31fe65211875f2c51129bf0729ce2dc7ce1a5afc6eaa1eb3a36296cb9e091375edfc408c727f6d54bba408da60b46c496a364c504adf47ee0496a9260fe223c8b23c14832635c3dff0dba8a0c8cdd957a77f18443b7782a9b6c7636b7d66df426350b959537e911888e45b2c0b218e50d03fdcfa7f758e8e60dd1a1996bc00000"
PrecertEntry = "00000000014b4981f0c800013760e2790f33a498f9b6c149fecfca3993954b536fbf36ad45d0a8415b79337d00047a30820476a00302010202100532298c396a3e25fcaa1977e827b5f3300d06092a864886f70d01010b0500306d310b300906035504061302555331163014060355040a130d47656f547275737420496e632e311f301d060355040b1316464f52205445535420505552504f534553204f4e4c59312530230603550403131c47656f54727573742045562053534c2054455354204341202d204734301e170d3135303230323030303030305a170d3136303232373233353935395a3081c331133011060b2b0601040182373c02010313024742311b3019060b2b0601040182373c020102140a43616c69666f726e6961311e301c060b2b0601040182373c0201010c0d4d6f756e7461696e2056696577310b30090603550406130247423113301106035504080c0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e2056696577311d301b060355040a0c1453796d616e74656320436f72706f726174696f6e3116301406035504030c0d736466656473662e747275737430820122300d06092a864886f70d01010105000382010f003082010a0282010100b19d97def39ff829c65ea099a3257298b33ff675451fdc5641a222347aee4a56201f4c1a406f2f19815d86dec1a611768e7d556c8e33a7f1b4c78db19cceae540e97ae1f0660b2ee4f8cff2045b84a9da228349744406eceaed0b08d46fdab3543b3d86ea708627a61a529b793a76adc6b776bc8d5b3d4fe21e2c4aa92cfd33b45e7412068e0683a2beffad1df2fc320b8ddbf02ffb603d2cf74798277fd9656b5acd45659b0e5d761e02dcf95c53095555a931ad5bfa9b4967c045d5f12de2d6b537cd93af2ad8b45e5540bd43279876d13e376fb649778e10dfa56165b901bd37e9dee4e46027b4c0732ca7ed64491862abaf6a24a4aaed8f49a0922ca4fb50203010001a38201d1308201cd30470603551d110440303e820d6b6a61736468662e7472757374820b73736466732e7472757374820d736466656473662e747275737482117777772e736466656473662e747275737430090603551d1304023000300e0603551d0f0101ff0404030205a0302b0603551d1f042430223020a01ea01c861a687474703a2f2f676d2e73796d63622e636f6d2f676d2e63726c3081a00603551d2004819830819530819206092b06010401f0220106308184303f06082b06010505070201163368747470733a2f2f7777772e67656f74727573742e636f6d2f7265736f75726365732f7265706f7369746f72792f6c6567616c304106082b0601050507020230350c3368747470733a2f2f7777772e67656f74727573742e636f6d2f7265736f75726365732f7265706f7369746f72792f6c6567616c301d0603551d250416301406082b0601050507030106082b06010505070302301f0603551d23041830168014b1699461abe6cb0c4ce759af5a498b1833c1e147305706082b06010505070101044b3049301f06082b060105050730018613687474703a2f2f676d2e73796d63642e636f6d302606082b06010505073002861a687474703a2f2f676d2e73796d63622e636f6d2f676d2e6372740000"
)
func TestUnmarshalMerkleTreeLeaf(t *testing.T) {
var tests = []struct {
in string // hex string
want LogEntryType
errstr string
}{
{CertEntry, X509LogEntryType, ""},
{PrecertEntry, PrecertLogEntryType, ""},
{"001234", 0, "LeafType: unhandled value"},
}
for _, test := range tests {
inData, _ := hex.DecodeString(test.in)
var got MerkleTreeLeaf
_, err := tls.Unmarshal(inData, &got)
if test.errstr != "" {
if err == nil {
t.Errorf("tls.Unmarshal(%s, &MerkleTreeLeaf)=%+v,nil; want error %q", test.in, got, test.errstr)
} else if !strings.Contains(err.Error(), test.errstr) {
t.Errorf("tls.Unmarshal(%s, &MerkleTreeLeaf)=nil,%q; want error %q", test.in, err.Error(), test.errstr)
}
continue
}
if err != nil {
t.Errorf("tls.Unmarshal(%s, &MerkleTreeLeaf)=nil,%q; want type %v", test.in, err.Error(), test.want)
continue
}
if got.Version != V1 {
t.Errorf("tls.Unmarshal(%s, &MerkleTreeLeaf)=version=%v,nil; want version 1", test.in, got.Version)
}
if got.LeafType != TimestampedEntryLeafType {
t.Errorf("tls.Unmarshal(%s, &MerkleTreeLeaf)=LeafType=%v,nil; want LeafType=%v", test.in, got.LeafType, TimestampedEntryLeafType)
}
if got.TimestampedEntry.EntryType != test.want {
t.Errorf("tls.Unmarshal(%s, &MerkleTreeLeaf)=EntryType=%v,nil; want LeafType=%v", test.in, got.TimestampedEntry.EntryType, test.want)
}
}
}
const (
validRootHash = "708981e91d1487c2a9ea901ab5a8d053c1348585afcdb5e107bf60c0c1d20fc0"
longRootHash = "708981e91d1487c2a9ea901ab5a8d053c1348585afcdb5e107bf60c0c1d20fc000"
shortRootHash = "708981e91d1487c2a9ea901ab5a8d053c1348585afcdb5e107bf60c0c1d20f"
validSignature = "040300473045022007fb5ae3cea8f076b534a01a9a19e60625c6cc70704c6c1a7c88b30d8f67d4af022100840d37b8f2f9ce134e74eefda6a0c2ad034d591b785cdc4973c4c4f5d03f0439"
longSignature = "040300473045022007fb5ae3cea8f076b534a01a9a19e60625c6cc70704c6c1a7c88b30d8f67d4af022100840d37b8f2f9ce134e74eefda6a0c2ad034d591b785cdc4973c4c4f5d03f043900"
)
func mustHexDecode(s string) []byte {
h, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return h
}
func TestToSignedTreeHead(t *testing.T) {
tests := []struct {
desc string
rootHash string
signature string
wantErr bool
}{
{
desc: "success",
rootHash: validRootHash,
signature: validSignature,
},
{
desc: "root hash too long",
rootHash: longRootHash,
signature: validSignature,
wantErr: true,
},
{
desc: "root hash too short",
rootHash: shortRootHash,
signature: validSignature,
wantErr: true,
},
{
desc: "signature trailing data",
rootHash: validRootHash,
signature: longSignature,
wantErr: true,
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
sthResponse := &GetSTHResponse{
TreeSize: 278437663,
Timestamp: 1527076172068,
SHA256RootHash: mustHexDecode(test.rootHash),
TreeHeadSignature: mustHexDecode(test.signature),
}
sth, err := sthResponse.ToSignedTreeHead()
if gotErr := (err != nil); gotErr != test.wantErr {
t.Errorf("GetSTHResponse.ToSignedTreeHead() = %+v, %v, want err? %t", sth, err, test.wantErr)
}
})
}
}

View File

@ -1,192 +0,0 @@
package x509_test
import (
"fmt"
"testing"
"github.com/google/certificate-transparency-go/x509"
)
func TestErrors(t *testing.T) {
var tests = []struct {
errs []x509.Error
want string
wantVerbose string
wantFatal bool
}{
{
errs: []x509.Error{
{Summary: "Error", Field: "a.b.c"},
},
want: "Error",
wantVerbose: "Error (a.b.c)",
},
{
errs: []x509.Error{
{
Summary: "Error",
Field: "a.b.c",
SpecRef: "RFC5280 s4.1.2.2",
SpecText: "The serial number MUST be a positive integer",
Category: x509.MalformedCertificate,
},
},
want: "Error",
wantVerbose: "Error (a.b.c: Certificate does not comply with MUST clause in spec: RFC5280 s4.1.2.2, 'The serial number MUST be a positive integer')",
},
{
errs: []x509.Error{
{
Summary: "Error",
Field: "a.b.c",
SpecRef: "RFC5280 s4.1.2.2",
SpecText: "The serial number MUST be a positive integer",
},
},
want: "Error",
wantVerbose: "Error (a.b.c: RFC5280 s4.1.2.2, 'The serial number MUST be a positive integer')",
},
{
errs: []x509.Error{
{
Summary: "Error",
Field: "a.b.c",
SpecRef: "RFC5280 s4.1.2.2",
Category: x509.MalformedCertificate,
},
},
want: "Error",
wantVerbose: "Error (a.b.c: Certificate does not comply with MUST clause in spec: RFC5280 s4.1.2.2)",
},
{
errs: []x509.Error{
{
Summary: "Error",
Field: "a.b.c",
SpecText: "The serial number MUST be a positive integer",
Category: x509.MalformedCertificate,
},
},
want: "Error",
wantVerbose: "Error (a.b.c: Certificate does not comply with MUST clause in spec: 'The serial number MUST be a positive integer')",
},
{
errs: []x509.Error{
{
Summary: "Error",
Field: "a.b.c",
SpecRef: "RFC5280 s4.1.2.2",
},
},
want: "Error",
wantVerbose: "Error (a.b.c: RFC5280 s4.1.2.2)",
},
{
errs: []x509.Error{
{
Summary: "Error",
Field: "a.b.c",
SpecText: "The serial number MUST be a positive integer",
},
},
want: "Error",
wantVerbose: "Error (a.b.c: 'The serial number MUST be a positive integer')",
},
{
errs: []x509.Error{
{
Summary: "Error",
Field: "a.b.c",
Category: x509.MalformedCertificate,
},
},
want: "Error",
wantVerbose: "Error (a.b.c: Certificate does not comply with MUST clause in spec)",
},
{
errs: []x509.Error{
{Summary: "Error"},
},
want: "Error",
wantVerbose: "Error",
},
{
errs: []x509.Error{
{Summary: "Error\nwith newline", Field: "x", Category: x509.InvalidASN1DER},
},
want: "Error\nwith newline",
wantVerbose: "Error\nwith newline (x: Invalid ASN.1 distinguished encoding)",
},
{
errs: []x509.Error{
{Summary: "Error1", Field: "a.b.c"},
{Summary: "Error2", Field: "a.b.c.d"},
{Summary: "Error3", Field: "x.y.z"},
},
want: "Errors:\n Error1\n Error2\n Error3",
wantVerbose: "Errors:\n Error1 (a.b.c)\n Error2 (a.b.c.d)\n Error3 (x.y.z)",
},
{
errs: []x509.Error{
{Summary: "Error1", Field: "a.b.c"},
{Summary: "Error2", Field: "a.b.c.d", Fatal: true},
{Summary: "Error3", Field: "x.y.z"},
},
want: "Errors:\n Error1\n Error2\n Error3",
wantVerbose: "Errors:\n Error1 (a.b.c)\n Error2 (a.b.c.d)\n Error3 (x.y.z)",
wantFatal: true,
},
}
for _, test := range tests {
errs := x509.Errors{Errs: test.errs}
if got := errs.Error(); got != test.want {
t.Errorf("Errors(%+v).Error()=%q; want %q", test.errs, got, test.want)
}
if got := errs.VerboseError(); got != test.wantVerbose {
t.Errorf("Errors(%+v).VerboseError()=%q; want %q", test.errs, got, test.wantVerbose)
}
if got := errs.Fatal(); got != test.wantFatal {
t.Errorf("Errors(%+v).Fatal()=%v; want %v", test.errs, got, test.wantFatal)
}
}
}
func TestErrorsAppend(t *testing.T) {
var errs x509.Errors
if got, want := errs.Error(), ""; got != want {
t.Errorf("Errors().Error()=%q; want %q", got, want)
}
if got, want := errs.Empty(), true; got != want {
t.Errorf("Errors().Empty()=%t; want %t", got, want)
}
errs.Errs = append(errs.Errs, x509.Error{
Summary: "Error",
Field: "a.b.c",
SpecRef: "RFC5280 s4.1.2.2"})
if got, want := errs.VerboseError(), "Error (a.b.c: RFC5280 s4.1.2.2)"; got != want {
t.Errorf("Errors(%+v).Error=%q; want %q", errs, got, want)
}
if got, want := errs.Empty(), false; got != want {
t.Errorf("Errors().Empty()=%t; want %t", got, want)
}
}
func TestErrorsFilter(t *testing.T) {
var errs x509.Errors
id := x509.ErrMaxID + 2
errs.AddID(id, "arg1", 2, "arg3")
baseErr := errs.Error()
errs.AddID(x509.ErrMaxID + 1)
if got, want := errs.Error(), fmt.Sprintf("Errors:\n %s\n E%03d: Unknown error ID %v: args []", baseErr, x509.ErrMaxID+1, x509.ErrMaxID+1); got != want {
t.Errorf("Errors(%+v).Error=%q; want %q", errs, got, want)
}
errList := fmt.Sprintf("%d, %d", x509.ErrMaxID+1, x509.ErrMaxID+1)
filter := x509.ErrorFilter(errList)
errs2 := errs.Filter(filter)
if got, want := errs2.Error(), baseErr; got != want {
t.Errorf("Errors(%+v).Error=%q; want %q", errs, got, want)
}
}

View File

@ -1,13 +0,0 @@
package x509
import (
"testing"
)
func TestTemplateIDs(t *testing.T) {
for id, template := range idToError {
if template.ID != id {
t.Errorf("idToError[%v].id=%v; want %v", id, template.ID, id)
}
}
}

View File

@ -1,135 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509_test
import (
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
"encoding/pem"
"fmt"
"github.com/google/certificate-transparency-go/x509"
)
func ExampleCertificate_Verify() {
// Verifying with a custom list of root certificates.
const rootPEM = `
-----BEGIN CERTIFICATE-----
MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
-----END CERTIFICATE-----`
const certPEM = `
-----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAw
WjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFp
bC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q
5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC
7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAa
BgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUF
BwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcy
LmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2Nz
cDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAf
BgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisG
AQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29t
L0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+
gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283
TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq
0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoW
RvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOh
yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
-----END CERTIFICATE-----`
// First, create the set of root certificates. For this example we only
// have one. It's also possible to omit this in order to use the
// default root set of the current operating system.
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM([]byte(rootPEM))
if !ok {
panic("failed to parse root certificate")
}
block, _ := pem.Decode([]byte(certPEM))
if block == nil {
panic("failed to parse certificate PEM")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
panic("failed to parse certificate: " + err.Error())
}
opts := x509.VerifyOptions{
DNSName: "mail.google.com",
Roots: roots,
}
if _, err := cert.Verify(opts); err != nil {
panic("failed to verify certificate: " + err.Error())
}
}
func ExampleParsePKIXPublicKey() {
const pubPEM = `
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlRuRnThUjU8/prwYxbty
WPT9pURI3lbsKMiB6Fn/VHOKE13p4D8xgOCADpdRagdT6n4etr9atzDKUSvpMtR3
CP5noNc97WiNCggBjVWhs7szEe8ugyqF23XwpHQ6uV1LKH50m92MbOWfCtjU9p/x
qhNpQQ1AZhqNy5Gevap5k8XzRmjSldNAFZMY7Yv3Gi+nyCwGwpVtBUwhuLzgNFK/
yDtw2WcWmUU7NuC8Q6MWvPebxVtCfVp/iQU6q60yyt6aGOBkhAX0LpKAEhKidixY
nP9PNVBvxgu3XZ4P36gZV6+ummKdBVnc3NqwBLu5+CcdRdusmHPHd5pHf4/38Z3/
6qU2a/fPvWzceVTEgZ47QjFMTCTmCwNt29cvi7zZeQzjtwQgn4ipN9NibRH/Ax/q
TbIzHfrJ1xa2RteWSdFjwtxi9C20HUkjXSeI4YlzQMH0fPX6KCE7aVePTOnB69I/
a9/q96DiXZajwlpq3wFctrs1oXqBp5DVrCIj8hU2wNgB7LtQ1mCtsYz//heai0K9
PhE4X6hiE0YmeAZjR0uHl8M/5aW9xCoJ72+12kKpWAa0SFRWLy6FejNYCYpkupVJ
yecLk/4L1W0l6jQQZnWErXZYe0PNFcmwGXy1Rep83kfBRNKRy5tvocalLlwXLdUk
AIU+2GKjyT3iMuzZxxFxPFMCAwEAAQ==
-----END PUBLIC KEY-----`
block, _ := pem.Decode([]byte(pubPEM))
if block == nil {
panic("failed to parse PEM block containing the public key")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic("failed to parse DER encoded public key: " + err.Error())
}
switch pub := pub.(type) {
case *rsa.PublicKey:
fmt.Println("pub is of type RSA:", pub)
case *dsa.PublicKey:
fmt.Println("pub is of type DSA:", pub)
case *ecdsa.PublicKey:
fmt.Println("pub is of type ECDSA:", pub)
default:
panic("unknown type of public key")
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,267 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509
import (
"bytes"
"encoding/hex"
"net"
"reflect"
"strings"
"testing"
"github.com/google/certificate-transparency-go/asn1"
"github.com/google/certificate-transparency-go/x509/pkix"
)
func TestParseGeneralNames(t *testing.T) {
var tests = []struct {
data string // as hex
want GeneralNames
wantErr string
}{
{
data: ("3012" +
("8210" + "7777772e676f6f676c652e636f2e756b")),
want: GeneralNames{
DNSNames: []string{"www.google.co.uk"},
},
},
{
data: ("3024" +
("8210" + "7777772e676f6f676c652e636f2e756b") +
("8610" + "7777772e676f6f676c652e636f2e756b")),
want: GeneralNames{
DNSNames: []string{"www.google.co.uk"},
URIs: []string{"www.google.co.uk"},
},
},
{
data: "0a0101",
wantErr: "failed to parse GeneralNames sequence",
},
{
data: "0a",
wantErr: "failed to parse GeneralNames:",
},
{
data: "03000a0101",
wantErr: "trailing data",
},
{
data: ("3005" + ("8703" + "010203")),
wantErr: "invalid IP length",
},
}
for _, test := range tests {
inData := fromHex(test.data)
var got GeneralNames
err := parseGeneralNames(inData, &got)
if err != nil {
if test.wantErr == "" {
t.Errorf("parseGeneralNames(%s)=%v; want nil", test.data, err)
} else if !strings.Contains(err.Error(), test.wantErr) {
t.Errorf("parseGeneralNames(%s)=%v; want %q", test.data, err, test.wantErr)
}
continue
}
if test.wantErr != "" {
t.Errorf("parseGeneralNames(%s)=%+v,nil; want %q", test.data, got, test.wantErr)
continue
}
if !reflect.DeepEqual(got, test.want) {
t.Errorf("parseGeneralNames(%s)=%+v; want %+v", test.data, got, test.want)
}
}
}
func TestParseGeneralName(t *testing.T) {
var tests = []struct {
data string // as hex
withMask bool
want GeneralNames
wantErr string
}{
{
data: ("a008" +
("0603" + "551d0e") + // OID: subject-key-id
("0a01" + "01")), // enum=1
want: GeneralNames{
OtherNames: []OtherName{
{
TypeID: OIDExtensionSubjectKeyId,
Value: asn1.RawValue{
Class: asn1.ClassUniversal,
Tag: asn1.TagEnum,
IsCompound: false,
Bytes: fromHex("01"),
FullBytes: fromHex("0a0101"),
},
},
},
},
},
{
data: ("8008" +
("0603" + "551d0e") + // OID: subject-key-id
("0a01" + "01")), // enum=1
wantErr: "not compound",
},
{
data: ("a005" +
("0603" + "551d0e")), // OID: subject-key-id
wantErr: "sequence truncated",
},
{
data: ("8110" + "77777740676f6f676c652e636f2e756b"),
want: GeneralNames{
EmailAddresses: []string{"www@google.co.uk"},
},
},
{
data: ("8210" + "7777772e676f6f676c652e636f2e756b"),
want: GeneralNames{
DNSNames: []string{"www.google.co.uk"},
},
},
{
data: ("844b" +
("3049" +
("310b" +
("3009" +
("0603" + "550406") +
("1302" + "5553"))) + // "US"
("3113" +
("3011" +
("0603" + "55040a") +
("130a" + "476f6f676c6520496e63"))) + // "Google Inc"
("3125" +
("3023" +
("0603" + "550403") +
("131c" + "476f6f676c6520496e7465726e657420417574686f72697479204732"))))), // "GoogleInternet Authority G2"
want: GeneralNames{
DirectoryNames: []pkix.Name{
{
Country: []string{"US"},
Organization: []string{"Google Inc"},
CommonName: "Google Internet Authority G2",
Names: []pkix.AttributeTypeAndValue{
{Type: pkix.OIDCountry, Value: "US"},
{Type: pkix.OIDOrganization, Value: "Google Inc"},
{Type: pkix.OIDCommonName, Value: "Google Internet Authority G2"},
},
},
},
},
},
{
data: ("8410" + "7777772e676f6f676c652e636f2e756b"),
wantErr: "failed to unmarshal GeneralNames.directoryName",
},
{
data: ("8610" + "7777772e676f6f676c652e636f2e756b"),
want: GeneralNames{
URIs: []string{"www.google.co.uk"},
},
},
{
data: ("8704" + "01020304"),
want: GeneralNames{
IPNets: []net.IPNet{{IP: net.IP{1, 2, 3, 4}}},
},
},
{
data: ("8708" + "01020304ffffff00"),
withMask: true,
want: GeneralNames{
IPNets: []net.IPNet{{IP: net.IP{1, 2, 3, 4}, Mask: net.IPMask{0xff, 0xff, 0xff, 0x00}}},
},
},
{
data: ("8710" + "01020304111213142122232431323334"),
want: GeneralNames{
IPNets: []net.IPNet{{IP: net.IP{1, 2, 3, 4, 0x11, 0x12, 0x13, 0x14, 0x21, 0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34}}},
},
},
{
data: ("8703" + "010203"),
wantErr: "invalid IP length",
},
{
data: ("8707" + "01020304ffffff"),
withMask: true,
wantErr: "invalid IP/mask length",
},
{
data: ("8803" + "551d0e"), // OID: subject-key-id
want: GeneralNames{
RegisteredIDs: []asn1.ObjectIdentifier{OIDExtensionSubjectKeyId},
},
},
{
data: ("8803" + "551d8e"),
wantErr: "syntax error",
},
{
data: ("9003" + "551d8e"),
wantErr: "unknown tag",
},
{
data: ("8803"),
wantErr: "data truncated",
},
}
for _, test := range tests {
inData := fromHex(test.data)
var got GeneralNames
_, err := parseGeneralName(inData, &got, test.withMask)
if err != nil {
if test.wantErr == "" {
t.Errorf("parseGeneralName(%s)=%v; want nil", test.data, err)
} else if !strings.Contains(err.Error(), test.wantErr) {
t.Errorf("parseGeneralName(%s)=%v; want %q", test.data, err, test.wantErr)
}
continue
}
if test.wantErr != "" {
t.Errorf("parseGeneralName(%s)=%+v,nil; want %q", test.data, got, test.wantErr)
continue
}
if !reflect.DeepEqual(got, test.want) {
t.Errorf("parseGeneralName(%s)=%+v; want %+v", test.data, got, test.want)
}
if got.Empty() {
t.Errorf("parseGeneralName(%s).Empty(%+v)=true; want false", test.data, got)
}
if gotLen, wantLen := got.Len(), 1; gotLen != wantLen {
t.Errorf("parseGeneralName(%s).Len(%+v)=%d; want %d", test.data, got, gotLen, wantLen)
}
if !bytes.Equal(inData, fromHex(test.data)) {
t.Errorf("parseGeneralName(%s) modified data to %x", test.data, inData)
}
// Wrap the GeneralName up in a SEQUENCE and check that we get the same result using parseGeneralNames.
if test.withMask {
continue
}
seqData := append([]byte{0x30, byte(len(inData))}, inData...)
var gotSeq GeneralNames
err = parseGeneralNames(seqData, &gotSeq)
if err != nil {
t.Errorf("parseGeneralNames(%x)=%v; want nil", seqData, err)
continue
}
if !reflect.DeepEqual(gotSeq, test.want) {
t.Errorf("parseGeneralNames(%x)=%+v; want %+v", seqData, gotSeq, test.want)
}
}
}
func fromHex(s string) []byte {
d, _ := hex.DecodeString(s)
return d
}

View File

@ -1,247 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509
import (
"bytes"
"crypto/rand"
"encoding/base64"
"encoding/pem"
"strings"
"testing"
)
func TestDecrypt(t *testing.T) {
for i, data := range testData {
t.Logf("test %v. %v", i, data.kind)
block, rest := pem.Decode(data.pemData)
if len(rest) > 0 {
t.Error("extra data")
}
der, err := DecryptPEMBlock(block, data.password)
if err != nil {
t.Error("decrypt failed: ", err)
continue
}
if _, err := ParsePKCS1PrivateKey(der); err != nil {
t.Error("invalid private key: ", err)
}
plainDER, err := base64.StdEncoding.DecodeString(data.plainDER)
if err != nil {
t.Fatal("cannot decode test DER data: ", err)
}
if !bytes.Equal(der, plainDER) {
t.Error("data mismatch")
}
}
}
func TestEncrypt(t *testing.T) {
for i, data := range testData {
t.Logf("test %v. %v", i, data.kind)
plainDER, err := base64.StdEncoding.DecodeString(data.plainDER)
if err != nil {
t.Fatal("cannot decode test DER data: ", err)
}
password := []byte("kremvax1")
block, err := EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", plainDER, password, data.kind)
if err != nil {
t.Error("encrypt: ", err)
continue
}
if !IsEncryptedPEMBlock(block) {
t.Error("PEM block does not appear to be encrypted")
}
if block.Type != "RSA PRIVATE KEY" {
t.Errorf("unexpected block type; got %q want %q", block.Type, "RSA PRIVATE KEY")
}
if block.Headers["Proc-Type"] != "4,ENCRYPTED" {
t.Errorf("block does not have correct Proc-Type header")
}
der, err := DecryptPEMBlock(block, password)
if err != nil {
t.Error("decrypt: ", err)
continue
}
if !bytes.Equal(der, plainDER) {
t.Errorf("data mismatch")
}
}
}
var testData = []struct {
kind PEMCipher
password []byte
pemData []byte
plainDER string
}{
{
kind: PEMCipherDES,
password: []byte("asdf"),
pemData: []byte(`
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-CBC,34F09A4FC8DE22B5
WXxy8kbZdiZvANtKvhmPBLV7eVFj2A5z6oAxvI9KGyhG0ZK0skfnt00C24vfU7m5
ICXeoqP67lzJ18xCzQfHjDaBNs53DSDT+Iz4e8QUep1xQ30+8QKX2NA2coee3nwc
6oM1cuvhNUDemBH2i3dKgMVkfaga0zQiiOq6HJyGSncCMSruQ7F9iWEfRbFcxFCx
qtHb1kirfGKEtgWTF+ynyco6+2gMXNu70L7nJcnxnV/RLFkHt7AUU1yrclxz7eZz
XOH9VfTjb52q/I8Suozq9coVQwg4tXfIoYUdT//O+mB7zJb9HI9Ps77b9TxDE6Gm
4C9brwZ3zg2vqXcwwV6QRZMtyll9rOpxkbw6NPlpfBqkc3xS51bbxivbO/Nve4KD
r12ymjFNF4stXCfJnNqKoZ50BHmEEUDu5Wb0fpVn82XrGw7CYc4iug==
-----END RSA PRIVATE KEY-----`),
plainDER: `
MIIBPAIBAAJBAPASZe+tCPU6p80AjHhDkVsLYa51D35e/YGa8QcZyooeZM8EHozo
KD0fNiKI+53bHdy07N+81VQ8/ejPcRoXPlsCAwEAAQJBAMTxIuSq27VpR+zZ7WJf
c6fvv1OBvpMZ0/d1pxL/KnOAgq2rD5hDtk9b0LGhTPgQAmrrMTKuSeGoIuYE+gKQ
QvkCIQD+GC1m+/do+QRurr0uo46Kx1LzLeSCrjBk34wiOp2+dwIhAPHfTLRXS2fv
7rljm0bYa4+eDZpz+E8RcXEgzhhvcQQ9AiAI5eHZJGOyml3MXnQjiPi55WcDOw0w
glcRgT6QCEtz2wIhANSyqaFtosIkHKqrDUGfz/bb5tqMYTAnBruVPaf/WEOBAiEA
9xORWeRG1tRpso4+dYy4KdDkuLPIO01KY6neYGm3BCM=`,
},
{
kind: PEMCipher3DES,
password: []byte("asdf"),
pemData: []byte(`
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,C1F4A6A03682C2C7
0JqVdBEH6iqM7drTkj+e2W/bE3LqakaiWhb9WUVonFkhyu8ca/QzebY3b5gCvAZQ
YwBvDcT/GHospKqPx+cxDHJNsUASDZws6bz8ZXWJGwZGExKzr0+Qx5fgXn44Ms3x
8g1ENFuTXtxo+KoNK0zuAMAqp66Llcds3Fjl4XR18QaD0CrVNAfOdgATWZm5GJxk
Fgx5f84nT+/ovvreG+xeOzWgvtKo0UUZVrhGOgfKLpa57adumcJ6SkUuBtEFpZFB
ldw5w7WC7d13x2LsRkwo8ZrDKgIV+Y9GNvhuCCkTzNP0V3gNeJpd201HZHR+9n3w
3z0VjR/MGqsfcy1ziEWMNOO53At3zlG6zP05aHMnMcZoVXadEK6L1gz++inSSDCq
gI0UJP4e3JVB7AkgYymYAwiYALAkoEIuanxoc50njJk=
-----END RSA PRIVATE KEY-----`),
plainDER: `
MIIBOwIBAAJBANOCXKdoNS/iP/MAbl9cf1/SF3P+Ns7ZeNL27CfmDh0O6Zduaax5
NBiumd2PmjkaCu7lQ5JOibHfWn+xJsc3kw0CAwEAAQJANX/W8d1Q/sCqzkuAn4xl
B5a7qfJWaLHndu1QRLNTRJPn0Ee7OKJ4H0QKOhQM6vpjRrz+P2u9thn6wUxoPsef
QQIhAP/jCkfejFcy4v15beqKzwz08/tslVjF+Yq41eJGejmxAiEA05pMoqfkyjcx
fyvGhpoOyoCp71vSGUfR2I9CR65oKh0CIC1Msjs66LlfJtQctRq6bCEtFCxEcsP+
eEjYo/Sk6WphAiEAxpgWPMJeU/shFT28gS+tmhjPZLpEoT1qkVlC14u0b3ECIQDX
tZZZxCtPAm7shftEib0VU77Lk8MsXJcx2C4voRsjEw==`,
},
{
kind: PEMCipherAES128,
password: []byte("asdf"),
pemData: []byte(`
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,D4492E793FC835CC038A728ED174F78A
EyfQSzXSjv6BaNH+NHdXRlkHdimpF9izWlugVJAPApgXrq5YldPe2aGIOFXyJ+QE
ZIG20DYqaPzJRjTEbPNZ6Es0S2JJ5yCpKxwJuDkgJZKtF39Q2i36JeGbSZQIuWJE
GZbBpf1jDH/pr0iGonuAdl2PCCZUiy+8eLsD2tyviHUkFLOB+ykYoJ5t8ngZ/B6D
33U43LLb7+9zD4y3Q9OVHqBFGyHcxCY9+9Qh4ZnFp7DTf6RY5TNEvE3s4g6aDpBs
3NbvRVvYTgs8K9EPk4K+5R+P2kD8J8KvEIGxVa1vz8QoCJ/jr7Ka2rvNgPCex5/E
080LzLHPCrXKdlr/f50yhNWq08ZxMWQFkui+FDHPDUaEELKAXV8/5PDxw80Rtybo
AVYoCVIbZXZCuCO81op8UcOgEpTtyU5Lgh3Mw5scQL0=
-----END RSA PRIVATE KEY-----`),
plainDER: `
MIIBOgIBAAJBAMBlj5FxYtqbcy8wY89d/S7n0+r5MzD9F63BA/Lpl78vQKtdJ5dT
cDGh/rBt1ufRrNp0WihcmZi7Mpl/3jHjiWECAwEAAQJABNOHYnKhtDIqFYj1OAJ3
k3GlU0OlERmIOoeY/cL2V4lgwllPBEs7r134AY4wMmZSBUj8UR/O4SNO668ElKPE
cQIhAOuqY7/115x5KCdGDMWi+jNaMxIvI4ETGwV40ykGzqlzAiEA0P9oEC3m9tHB
kbpjSTxaNkrXxDgdEOZz8X0uOUUwHNsCIAwzcSCiGLyYJTULUmP1ESERfW1mlV78
XzzESaJpIM/zAiBQkSTcl9VhcJreQqvjn5BnPZLP4ZHS4gPwJAGdsj5J4QIhAOVR
B3WlRNTXR2WsJ5JdByezg9xzdXzULqmga0OE339a`,
},
{
kind: PEMCipherAES192,
password: []byte("asdf"),
pemData: []byte(`
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-192-CBC,E2C9FB02BCA23ADE1829F8D8BC5F5369
cqVslvHqDDM6qwU6YjezCRifXmKsrgEev7ng6Qs7UmDJOpHDgJQZI9fwMFUhIyn5
FbCu1SHkLMW52Ld3CuEqMnzWMlhPrW8tFvUOrMWPYSisv7nNq88HobZEJcUNL2MM
Y15XmHW6IJwPqhKyLHpWXyOCVEh4ODND2nV15PCoi18oTa475baxSk7+1qH7GuIs
Rb7tshNTMqHbCpyo9Rn3UxeFIf9efdl8YLiMoIqc7J8E5e9VlbeQSdLMQOgDAQJG
ReUtTw8exmKsY4gsSjhkg5uiw7/ZB1Ihto0qnfQJgjGc680qGkT1d6JfvOfeYAk6
xn5RqS/h8rYAYm64KnepfC9vIujo4NqpaREDmaLdX5MJPQ+SlytITQvgUsUq3q/t
Ss85xjQEZH3hzwjQqdJvmA4hYP6SUjxYpBM+02xZ1Xw=
-----END RSA PRIVATE KEY-----`),
plainDER: `
MIIBOwIBAAJBAMGcRrZiNNmtF20zyS6MQ7pdGx17aFDl+lTl+qnLuJRUCMUG05xs
OmxmL/O1Qlf+bnqR8Bgg65SfKg21SYuLhiMCAwEAAQJBAL94uuHyO4wux2VC+qpj
IzPykjdU7XRcDHbbvksf4xokSeUFjjD3PB0Qa83M94y89ZfdILIqS9x5EgSB4/lX
qNkCIQD6cCIqLfzq/lYbZbQgAAjpBXeQVYsbvVtJrPrXJAlVVQIhAMXpDKMeFPMn
J0g2rbx1gngx0qOa5r5iMU5w/noN4W2XAiBjf+WzCG5yFvazD+dOx3TC0A8+4x3P
uZ3pWbaXf5PNuQIgAcdXarvhelH2w2piY1g3BPeFqhzBSCK/yLGxR82KIh8CIQDD
+qGKsd09NhQ/G27y/DARzOYtml1NvdmCQAgsDIIOLA==`,
},
{
kind: PEMCipherAES256,
password: []byte("asdf"),
pemData: []byte(`
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,8E7ED5CD731902CE938957A886A5FFBD
4Mxr+KIzRVwoOP0wwq6caSkvW0iS+GE2h2Ov/u+n9ZTMwL83PRnmjfjzBgfRZLVf
JFPXxUK26kMNpIdssNnqGOds+DhB+oSrsNKoxgxSl5OBoYv9eJTVYm7qOyAFIsjr
DRKAcjYCmzfesr7PVTowwy0RtHmYwyXMGDlAzzZrEvaiySFFmMyKKvtoavwaFoc7
Pz3RZScwIuubzTGJ1x8EzdffYOsdCa9Mtgpp3L136+23dOd6L/qK2EG2fzrJSHs/
2XugkleBFSMKzEp9mxXKRfa++uidQvMZTFLDK9w5YjrRvMBo/l2BoZIsq0jAIE1N
sv5Z/KwlX+3MDEpPQpUwGPlGGdLnjI3UZ+cjgqBcoMiNc6HfgbBgYJSU6aDSHuCk
clCwByxWkBNgJ2GrkwNrF26v+bGJJJNR4SKouY1jQf0=
-----END RSA PRIVATE KEY-----`),
plainDER: `
MIIBOgIBAAJBAKy3GFkstoCHIEeUU/qO8207m8WSrjksR+p9B4tf1w5k+2O1V/GY
AQ5WFCApItcOkQe/I0yZZJk/PmCqMzSxrc8CAwEAAQJAOCAz0F7AW9oNelVQSP8F
Sfzx7O1yom+qWyAQQJF/gFR11gpf9xpVnnyu1WxIRnDUh1LZwUsjwlDYb7MB74id
oQIhANPcOiLwOPT4sIUpRM5HG6BF1BI7L77VpyGVk8xNP7X/AiEA0LMHZtk4I+lJ
nClgYp4Yh2JZ1Znbu7IoQMCEJCjwKDECIGd8Dzm5tViTkUW6Hs3Tlf73nNs65duF
aRnSglss8I3pAiEAonEnKruawgD8RavDFR+fUgmQiPz4FnGGeVgfwpGG1JECIBYq
PXHYtPqxQIbD2pScR5qum7iGUh11lEUPkmt+2uqS`,
},
{
// generated with:
// openssl genrsa -aes128 -passout pass:asdf -out server.orig.key 128
kind: PEMCipherAES128,
password: []byte("asdf"),
pemData: []byte(`
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7
6ei/MlytjE0FFgZOGQ+jrwomKfpl8kdefeE0NSt/DMRrw8OacHAzBNi3pPEa0eX3
eND9l7C9meCirWovjj9QWVHrXyugFuDIqgdhQ8iHTgCfF3lrmcttVrbIfMDw+smD
hTP8O1mS/MHl92NE0nhv0w==
-----END RSA PRIVATE KEY-----`),
plainDER: `
MGMCAQACEQC6ssxmYuauuHGOCDAI54RdAgMBAAECEQCWIn6Yv2O+kBcDF7STctKB
AgkA8SEfu/2i3g0CCQDGNlXbBHX7kQIIK3Ww5o0cYbECCQDCimPb0dYGsQIIeQ7A
jryIst8=`,
},
}
const incompleteBlockPEM = `
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7
6L8yXK2MTQUWBk4ZD6OvCiYp+mXyR1594TQ1K38MxGvDw5pwcDME2Lek8RrR5fd40P2XsL2Z4KKt
ai+OP1BZUetfK6AW4MiqB2FDyIdOAJ8XeWuZy21Wtsh8wPD6yYOFM/w7WZL8weX3Y0TSeG/T
-----END RSA PRIVATE KEY-----`
func TestIncompleteBlock(t *testing.T) {
// incompleteBlockPEM contains ciphertext that is not a multiple of the
// block size. This previously panicked. See #11215.
block, _ := pem.Decode([]byte(incompleteBlockPEM))
_, err := DecryptPEMBlock(block, []byte("foo"))
if err == nil {
t.Fatal("Bad PEM data decrypted successfully")
}
const expectedSubstr = "block size"
if e := err.Error(); !strings.Contains(e, expectedSubstr) {
t.Fatalf("Expected error containing %q but got: %q", expectedSubstr, e)
}
}

View File

@ -1,109 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"encoding/hex"
"reflect"
"testing"
)
// Generated using:
// openssl genrsa 1024 | openssl pkcs8 -topk8 -nocrypt
var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031`
// Generated using:
// openssl ecparam -genkey -name secp224r1 | openssl pkcs8 -topk8 -nocrypt
var pkcs8P224PrivateKeyHex = `3078020100301006072a8648ce3d020106052b810400210461305f020101041cca3d72b3e88fed2684576dad9b80a9180363a5424986900e3abcab3fa13c033a0004f8f2a6372872a4e61263ed893afb919576a4cacfecd6c081a2cbc76873cf4ba8530703c6042b3a00e2205087e87d2435d2e339e25702fae1`
// Generated using:
// openssl ecparam -genkey -name secp256r1 | openssl pkcs8 -topk8 -nocrypt
var pkcs8P256PrivateKeyHex = `308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420dad6b2f49ca774c36d8ae9517e935226f667c929498f0343d2424d0b9b591b43a14403420004b9c9b90095476afe7b860d8bd43568cab7bcb2eed7b8bf2fa0ce1762dd20b04193f859d2d782b1e4cbfd48492f1f533113a6804903f292258513837f07fda735`
// Generated using:
// openssl ecparam -genkey -name secp384r1 | openssl pkcs8 -topk8 -nocrypt
var pkcs8P384PrivateKeyHex = `3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010104309bf832f6aaaeacb78ce47ffb15e6fd0fd48683ae79df6eca39bfb8e33829ac94aa29d08911568684c2264a08a4ceb679a164036200049070ad4ed993c7770d700e9f6dc2baa83f63dd165b5507f98e8ff29b5d2e78ccbe05c8ddc955dbf0f7497e8222cfa49314fe4e269459f8e880147f70d785e530f2939e4bf9f838325bb1a80ad4cf59272ae0e5efe9a9dc33d874492596304bd3`
// Generated using:
// openssl ecparam -genkey -name secp521r1 | openssl pkcs8 -topk8 -nocrypt
//
// Note that OpenSSL will truncate the private key if it can (i.e. it emits it
// like an integer, even though it's an OCTET STRING field). Thus if you
// regenerate this you may, randomly, find that it's a byte shorter than
// expected and the Go test will fail to recreate it exactly.
var pkcs8P521PrivateKeyHex = `3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044200cfe0b87113a205cf291bb9a8cd1a74ac6c7b2ebb8199aaa9a5010d8b8012276fa3c22ac913369fa61beec2a3b8b4516bc049bde4fb3b745ac11b56ab23ac52e361a1818903818600040138f75acdd03fbafa4f047a8e4b272ba9d555c667962b76f6f232911a5786a0964e5edea6bd21a6f8725720958de049c6e3e6661c1c91b227cebee916c0319ed6ca003db0a3206d372229baf9dd25d868bf81140a518114803ce40c1855074d68c4e9dab9e65efba7064c703b400f1767f217dac82715ac1f6d88c74baf47a7971de4ea`
func TestPKCS8(t *testing.T) {
tests := []struct {
name string
keyHex string
keyType reflect.Type
curve elliptic.Curve
}{
{
name: "RSA private key",
keyHex: pkcs8RSAPrivateKeyHex,
keyType: reflect.TypeOf(&rsa.PrivateKey{}),
},
{
name: "P-224 private key",
keyHex: pkcs8P224PrivateKeyHex,
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
curve: elliptic.P224(),
},
{
name: "P-256 private key",
keyHex: pkcs8P256PrivateKeyHex,
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
curve: elliptic.P256(),
},
{
name: "P-384 private key",
keyHex: pkcs8P384PrivateKeyHex,
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
curve: elliptic.P384(),
},
{
name: "P-521 private key",
keyHex: pkcs8P521PrivateKeyHex,
keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
curve: elliptic.P521(),
},
}
for _, test := range tests {
derBytes, err := hex.DecodeString(test.keyHex)
if err != nil {
t.Errorf("%s: failed to decode hex: %s", test.name, err)
continue
}
privKey, err := ParsePKCS8PrivateKey(derBytes)
if err != nil {
t.Errorf("%s: failed to decode PKCS#8: %s", test.name, err)
continue
}
if reflect.TypeOf(privKey) != test.keyType {
t.Errorf("%s: decoded PKCS#8 returned unexpected key type: %T", test.name, privKey)
continue
}
if ecKey, isEC := privKey.(*ecdsa.PrivateKey); isEC && ecKey.Curve != test.curve {
t.Errorf("%s: decoded PKCS#8 returned unexpected curve %#v", test.name, ecKey.Curve)
continue
}
reserialised, err := MarshalPKCS8PrivateKey(privKey)
if err != nil {
t.Errorf("%s: failed to marshal into PKCS#8: %s", test.name, err)
continue
}
if !bytes.Equal(derBytes, reserialised) {
t.Errorf("%s: marshalled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes)
continue
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509
import (
"runtime"
"testing"
"time"
)
func TestSystemRoots(t *testing.T) {
switch runtime.GOARCH {
case "arm", "arm64":
t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
}
switch runtime.GOOS {
case "darwin":
t.Skipf("skipping on %s/%s until cgo part of golang.org/issue/16532 has been implemented.", runtime.GOOS, runtime.GOARCH)
}
t0 := time.Now()
sysRoots := systemRootsPool() // actual system roots
sysRootsDuration := time.Since(t0)
t1 := time.Now()
execRoots, err := execSecurityRoots() // non-cgo roots
execSysRootsDuration := time.Since(t1)
if err != nil {
t.Fatalf("failed to read system roots: %v", err)
}
t.Logf(" cgo sys roots: %v", sysRootsDuration)
t.Logf("non-cgo sys roots: %v", execSysRootsDuration)
for _, tt := range []*CertPool{sysRoots, execRoots} {
if tt == nil {
t.Fatal("no system roots")
}
// On Mavericks, there are 212 bundled certs, at least
// there was at one point in time on one machine.
// (Maybe it was a corp laptop with extra certs?)
// Other OS X users report
// 135, 142, 145... Let's try requiring at least 100,
// since this is just a sanity check.
t.Logf("got %d roots", len(tt.certs))
if want, have := 100, len(tt.certs); have < want {
t.Fatalf("want at least %d system roots, have %d", want, have)
}
}
// Check that the two cert pools are roughly the same;
// |A∩B| > max(|A|, |B|) / 2 should be a reasonably robust check.
isect := make(map[string]bool, len(sysRoots.certs))
for _, c := range sysRoots.certs {
isect[string(c.Raw)] = true
}
have := 0
for _, c := range execRoots.certs {
if isect[string(c.Raw)] {
have++
}
}
var want int
if nsys, nexec := len(sysRoots.certs), len(execRoots.certs); nsys > nexec {
want = nsys / 2
} else {
want = nexec / 2
}
if have < want {
t.Errorf("insufficient overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
}
}

View File

@ -1,127 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build dragonfly freebsd linux netbsd openbsd solaris
package x509
import (
"fmt"
"os"
"testing"
)
const (
testDir = "testdata"
testDirCN = "test-dir"
testFile = "test-file.crt"
testFileCN = "test-file"
testMissing = "missing"
)
func TestEnvVars(t *testing.T) {
testCases := []struct {
name string
fileEnv string
dirEnv string
files []string
dirs []string
cns []string
}{
{
// Environment variables override the default locations preventing fall through.
name: "override-defaults",
fileEnv: testMissing,
dirEnv: testMissing,
files: []string{testFile},
dirs: []string{testDir},
cns: nil,
},
{
// File environment overrides default file locations.
name: "file",
fileEnv: testFile,
dirEnv: "",
files: nil,
dirs: nil,
cns: []string{testFileCN},
},
{
// Directory environment overrides default directory locations.
name: "dir",
fileEnv: "",
dirEnv: testDir,
files: nil,
dirs: nil,
cns: []string{testDirCN},
},
{
// File & directory environment overrides both default locations.
name: "file+dir",
fileEnv: testFile,
dirEnv: testDir,
files: nil,
dirs: nil,
cns: []string{testFileCN, testDirCN},
},
{
// Environment variable empty / unset uses default locations.
name: "empty-fall-through",
fileEnv: "",
dirEnv: "",
files: []string{testFile},
dirs: []string{testDir},
cns: []string{testFileCN, testDirCN},
},
}
// Save old settings so we can restore before the test ends.
origCertFiles, origCertDirectories := certFiles, certDirectories
origFile, origDir := os.Getenv(certFileEnv), os.Getenv(certDirEnv)
defer func() {
certFiles = origCertFiles
certDirectories = origCertDirectories
os.Setenv(certFileEnv, origFile)
os.Setenv(certDirEnv, origDir)
}()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if err := os.Setenv(certFileEnv, tc.fileEnv); err != nil {
t.Fatalf("setenv %q failed: %v", certFileEnv, err)
}
if err := os.Setenv(certDirEnv, tc.dirEnv); err != nil {
t.Fatalf("setenv %q failed: %v", certDirEnv, err)
}
certFiles, certDirectories = tc.files, tc.dirs
r, err := loadSystemRoots()
if err != nil {
t.Fatal("unexpected failure:", err)
}
if r == nil {
if tc.cns == nil {
// Expected nil
return
}
t.Fatal("nil roots")
}
// Verify that the returned certs match, otherwise report where the mismatch is.
for i, cn := range tc.cns {
if i >= len(r.certs) {
t.Errorf("missing cert %v @ %v", cn, i)
} else if r.certs[i].Subject.CommonName != cn {
fmt.Printf("%#v\n", r.certs[0].Subject)
t.Errorf("unexpected cert common name %q, want %q", r.certs[i].Subject.CommonName, cn)
}
}
if len(r.certs) > len(tc.cns) {
t.Errorf("got %v certs, which is more than %v wanted", len(r.certs), len(tc.cns))
}
})
}
}

View File

@ -1,44 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509
import (
"bytes"
"encoding/hex"
"testing"
)
var ecKeyTests = []struct {
derHex string
shouldReserialize bool
}{
// Generated using:
// openssl ecparam -genkey -name secp384r1 -outform PEM
{"3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50", true},
// This key was generated by GnuTLS and has illegal zero-padding of the
// private key. See https://golang.org/issues/13699.
{"3078020101042100f9f43a04b9bdc3ab01f53be6df80e7a7bc3eaf7b87fc24e630a4a0aa97633645a00a06082a8648ce3d030107a1440342000441a51bc318461b4c39a45048a16d4fc2a935b1ea7fe86e8c1fa219d6f2438f7c7fd62957d3442efb94b6a23eb0ea66dda663dc42f379cda6630b21b7888a5d3d", false},
// This was generated using an old version of OpenSSL and is missing a
// leading zero byte in the private key that should be present.
{"3081db0201010441607b4f985774ac21e633999794542e09312073480baa69550914d6d43d8414441e61b36650567901da714f94dffb3ce0e2575c31928a0997d51df5c440e983ca17a00706052b81040023a181890381860004001661557afedd7ac8d6b70e038e576558c626eb62edda36d29c3a1310277c11f67a8c6f949e5430a37dcfb95d902c1b5b5379c389873b9dd17be3bdb088a4774a7401072f830fb9a08d93bfa50a03dd3292ea07928724ddb915d831917a338f6b0aecfbc3cf5352c4a1295d356890c41c34116d29eeb93779aab9d9d78e2613437740f6", false},
}
func TestParseECPrivateKey(t *testing.T) {
for i, test := range ecKeyTests {
derBytes, _ := hex.DecodeString(test.derHex)
key, err := ParseECPrivateKey(derBytes)
if err != nil {
t.Fatalf("#%d: failed to decode EC private key: %s", i, err)
}
serialized, err := MarshalECPrivateKey(key)
if err != nil {
t.Fatalf("#%d: failed to encode EC private key: %s", i, err)
}
matches := bytes.Equal(serialized, derBytes)
if matches != test.shouldReserialize {
t.Fatalf("#%d: when serializing key: matches=%t, should match=%t: original %x, reserialized %x", i, matches, test.shouldReserialize, serialized, derBytes)
}
}
}

View File

@ -1,19 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509
import "syscall"
func init() {
v, err := syscall.GetVersion()
if err != nil {
return
}
if major := byte(v); major < 6 {
// Windows XP SP2 and Windows 2003 do not support SHA2.
// http://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx
supportSHA2 = false
}
}

View File

@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIJAL8a/lsnspOqMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
dHMxETAPBgNVBAMMCHRlc3QtZGlyMB4XDTE3MDIwMTIzNTAyN1oXDTI3MDEzMDIz
NTAyN1owTDELMAkGA1UEBhMCVUsxEzARBgNVBAgMClRlc3QtU3RhdGUxFTATBgNV
BAoMDEdvbGFuZyBUZXN0czERMA8GA1UEAwwIdGVzdC1kaXIwggIiMA0GCSqGSIb3
DQEBAQUAA4ICDwAwggIKAoICAQDzBoi43Yn30KN13PKFHu8LA4UmgCRToTukLItM
WK2Je45grs/axg9n3YJOXC6hmsyrkOnyBcx1xVNgSrOAll7fSjtChRIX72Xrloxu
XewtWVIrijqz6oylbvEmbRT3O8uynu5rF82Pmdiy8oiSfdywjKuPnE0hjV1ZSCql
MYcXqA+f0JFD8kMv4pbtxjGH8f2DkYQz+hHXLrJH4/MEYdVMQXoz/GDzLyOkrXBN
hpMaBBqg1p0P+tRdfLXuliNzA9vbZylzpF1YZ0gvsr0S5Y6LVtv7QIRygRuLY4kF
k+UYuFq8NrV8TykS7FVnO3tf4XcYZ7r2KV5FjYSrJtNNo85BV5c3xMD3fJ2XcOWk
+oD1ATdgAM3aKmSOxNtNItKKxBe1mkqDH41NbWx7xMad78gDznyeT0tjEOltN2bM
uXU1R/jgR/vq5Ec0AhXJyL/ziIcmuV2fSl/ZxT4ARD+16tgPiIx+welTf0v27/JY
adlfkkL5XsPRrbSguISrj7JeaO/gjG3KnDVHcZvYBpDfHqRhCgrosfe26TZcTXx2
cRxOfvBjMz1zJAg+esuUzSkerreyRhzD7RpeZTwi6sxvx82MhYMbA3w1LtgdABio
9JRqZy3xqsIbNv7N46WO/qXL1UMRKb1UyHeW8g8btboz+B4zv1U0Nj+9qxPBbQui
dgL9LQIDAQABo1AwTjAdBgNVHQ4EFgQUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwHwYD
VR0jBBgwFoAUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwDAYDVR0TBAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAvEVnUYsIOt87rggmLPqEueynkuQ+562M8EDHSQl82zbe
xDCxeg3DvPgKb+RvaUdt1362z/szK10SoeMgx6+EQLoV9LiVqXwNqeYfixrhrdw3
ppAhYYhymdkbUQCEMHypmXP1vPhAz4o8Bs+eES1M+zO6ErBiD7SqkmBElT+GixJC
6epC9ZQFs+dw3lPlbiZSsGE85sqc3VAs0/JgpL/pb1/Eg4s0FUhZD2C2uWdSyZGc
g0/v3aXJCp4j/9VoNhI1WXz3M45nysZIL5OQgXymLqJElQa1pZ3Wa4i/nidvT4AT
Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt
3UFGzYXDjxYnK2frQfjLS8stOQIqSrGthW6x0fdkVx0y8BByvd5J6+JmZl4UZfzA
m99VxXSt4B9x6BvnY7ktzcFDOjtuLc4B/7yg9fv1eQuStA4cHGGAttsCg1X/Kx8W
PvkkeH0UWDZ9vhH9K36703z89da6MWF+bz92B0+4HoOmlVaXRkvblsNaynJnL0LC
Ayry7QBxuh5cMnDdRwJB3AVJIiJ1GVpb7aGvBOnx+s2lwRv9HWtghb+cbwwktx1M
JHyBf3GZNSWTpKY7cD8V+NnBv3UuioOVVo+XAU4LF/bYUjdRpxWADJizNtZrtFo=
-----END CERTIFICATE-----

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
// 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 x509util
import (
"encoding/pem"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"github.com/google/certificate-transparency-go/x509"
)
// ReadPossiblePEMFile loads data from a file which may be in DER format
// or may be in PEM format (with the given blockname).
func ReadPossiblePEMFile(filename, blockname string) ([][]byte, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("%s: failed to read data: %v", filename, err)
}
return dePEM(data, blockname), nil
}
// ReadPossiblePEMURL attempts to determine if the given target is a local file or a
// URL, and return the file contents regardless. It also copes with either PEM or DER
// format data.
func ReadPossiblePEMURL(target, blockname string) ([][]byte, error) {
if !strings.HasPrefix(target, "http://") && !strings.HasPrefix(target, "https://") {
// Assume it's a filename
return ReadPossiblePEMFile(target, blockname)
}
rsp, err := http.Get(target)
if err != nil {
return nil, fmt.Errorf("failed to http.Get(%q): %v", target, err)
}
data, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return nil, fmt.Errorf("failed to ioutil.ReadAll(%q): %v", target, err)
}
return dePEM(data, blockname), nil
}
func dePEM(data []byte, blockname string) [][]byte {
var results [][]byte
if strings.Contains(string(data), "BEGIN "+blockname) {
rest := data
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
if block.Type == blockname {
results = append(results, block.Bytes)
}
}
} else {
results = append(results, data)
}
return results
}
// ReadFileOrURL returns the data from a target which may be either a filename
// or an HTTP(S) URL.
func ReadFileOrURL(target string, client *http.Client) ([]byte, error) {
u, err := url.Parse(target)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
return ioutil.ReadFile(target)
}
rsp, err := client.Get(u.String())
if err != nil {
return nil, fmt.Errorf("failed to http.Get(%q): %v", target, err)
}
return ioutil.ReadAll(rsp.Body)
}
// GetIssuer attempts to retrieve the issuer for a certificate, by examining
// the cert's Authority Information Access extension (if present) for the
// issuer's URL and retrieving from there.
func GetIssuer(cert *x509.Certificate, client *http.Client) (*x509.Certificate, error) {
if len(cert.IssuingCertificateURL) == 0 {
return nil, nil
}
issuerURL := cert.IssuingCertificateURL[0]
rsp, err := client.Get(issuerURL)
if err != nil || rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get issuer from %q: %v", issuerURL, err)
}
defer rsp.Body.Close()
body, err := ioutil.ReadAll(rsp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read issuer from %q: %v", issuerURL, err)
}
issuers, err := x509.ParseCertificates(body)
if err != nil {
return nil, fmt.Errorf("failed to parse issuer cert: %v", err)
}
return issuers[0], nil
}

View File

@ -1,26 +0,0 @@
// 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 x509util
import "github.com/google/certificate-transparency-go/x509"
// Fuzz is a go-fuzz (https://github.com/dvyukov/go-fuzz) entrypoint
// for fuzzing the parsing of X509 certificates.
func Fuzz(data []byte) int {
if _, err := x509.ParseCertificate(data); err == nil {
return 1
}
return 0
}

View File

@ -1,169 +0,0 @@
// 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 x509util
import (
"bytes"
"encoding/hex"
"fmt"
"strconv"
"github.com/google/certificate-transparency-go/x509"
"github.com/google/certificate-transparency-go/x509/pkix"
)
// RevocationReasonToString generates a string describing a revocation reason code.
func RevocationReasonToString(reason x509.RevocationReasonCode) string {
switch reason {
case x509.Unspecified:
return "Unspecified"
case x509.KeyCompromise:
return "Key Compromise"
case x509.CACompromise:
return "CA Compromise"
case x509.AffiliationChanged:
return "Affiliation Changed"
case x509.Superseded:
return "Superseded"
case x509.CessationOfOperation:
return "Cessation Of Operation"
case x509.CertificateHold:
return "Certificate Hold"
case x509.RemoveFromCRL:
return "Remove From CRL"
case x509.PrivilegeWithdrawn:
return "Privilege Withdrawn"
case x509.AACompromise:
return "AA Compromise"
default:
return strconv.Itoa(int(reason))
}
}
// CRLToString generates a string describing the given certificate revocation list.
// The output roughly resembles that from openssl crl -text.
func CRLToString(crl *x509.CertificateList) string {
var result bytes.Buffer
var showCritical = func(critical bool) {
if critical {
result.WriteString(" critical")
}
result.WriteString("\n")
}
result.WriteString("Certificate Revocation List (CRL):\n")
result.WriteString(fmt.Sprintf(" Version: %d (%#x)\n", crl.TBSCertList.Version+1, crl.TBSCertList.Version))
result.WriteString(fmt.Sprintf(" Signature Algorithm: %v\n", x509.SignatureAlgorithmFromAI(crl.TBSCertList.Signature)))
var issuer pkix.Name
issuer.FillFromRDNSequence(&crl.TBSCertList.Issuer)
result.WriteString(fmt.Sprintf(" Issuer: %v\n", NameToString(issuer)))
result.WriteString(fmt.Sprintf(" Last Update: %v\n", crl.TBSCertList.ThisUpdate))
result.WriteString(fmt.Sprintf(" Next Update: %v\n", crl.TBSCertList.NextUpdate))
if len(crl.TBSCertList.Extensions) > 0 {
result.WriteString(" CRL extensions:\n")
}
count, critical := OIDInExtensions(x509.OIDExtensionAuthorityKeyId, crl.TBSCertList.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Authority Key Identifier:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" keyid:%v\n", hex.EncodeToString(crl.TBSCertList.AuthorityKeyID)))
}
count, critical = OIDInExtensions(x509.OIDExtensionIssuerAltName, crl.TBSCertList.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Issuer Alt Name:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" %s\n", GeneralNamesToString(&crl.TBSCertList.IssuerAltNames)))
}
count, critical = OIDInExtensions(x509.OIDExtensionCRLNumber, crl.TBSCertList.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 CRLNumber:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" %d\n", crl.TBSCertList.CRLNumber))
}
count, critical = OIDInExtensions(x509.OIDExtensionDeltaCRLIndicator, crl.TBSCertList.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Delta CRL Indicator:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" %d\n", crl.TBSCertList.BaseCRLNumber))
}
count, critical = OIDInExtensions(x509.OIDExtensionIssuingDistributionPoint, crl.TBSCertList.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Issuing Distribution Point:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" %s\n", GeneralNamesToString(&crl.TBSCertList.IssuingDPFullNames)))
}
count, critical = OIDInExtensions(x509.OIDExtensionFreshestCRL, crl.TBSCertList.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Freshest CRL:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" Full Name:\n"))
var buf bytes.Buffer
for _, pt := range crl.TBSCertList.FreshestCRLDistributionPoint {
commaAppend(&buf, "URI:"+pt)
}
result.WriteString(fmt.Sprintf(" %v\n", buf.String()))
}
count, critical = OIDInExtensions(x509.OIDExtensionAuthorityInfoAccess, crl.TBSCertList.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" Authority Information Access:"))
showCritical(critical)
var issuerBuf bytes.Buffer
for _, issuer := range crl.TBSCertList.IssuingCertificateURL {
commaAppend(&issuerBuf, "URI:"+issuer)
}
if issuerBuf.Len() > 0 {
result.WriteString(fmt.Sprintf(" CA Issuers - %v\n", issuerBuf.String()))
}
var ocspBuf bytes.Buffer
for _, ocsp := range crl.TBSCertList.OCSPServer {
commaAppend(&ocspBuf, "URI:"+ocsp)
}
if ocspBuf.Len() > 0 {
result.WriteString(fmt.Sprintf(" OCSP - %v\n", ocspBuf.String()))
}
// TODO(drysdale): Display other GeneralName types
}
result.WriteString("\n")
result.WriteString("Revoked Certificates:\n")
for _, c := range crl.TBSCertList.RevokedCertificates {
result.WriteString(fmt.Sprintf(" Serial Number: %d (%#[1]x)\n", c.SerialNumber))
result.WriteString(fmt.Sprintf(" Revocation Date : %v\n", c.RevocationTime))
count, critical = OIDInExtensions(x509.OIDExtensionCRLReasons, c.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 CRL Reason Code:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" %s\n", RevocationReasonToString(c.RevocationReason)))
}
count, critical = OIDInExtensions(x509.OIDExtensionInvalidityDate, c.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" Invalidity Date:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" %s\n", c.InvalidityDate))
}
count, critical = OIDInExtensions(x509.OIDExtensionCertificateIssuer, c.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" Issuer:"))
showCritical(critical)
result.WriteString(fmt.Sprintf(" %s\n", GeneralNamesToString(&c.Issuer)))
}
}
result.WriteString(fmt.Sprintf(" Signature Algorithm: %v\n", x509.SignatureAlgorithmFromAI(crl.SignatureAlgorithm)))
appendHexData(&result, crl.SignatureValue.Bytes, 18, " ")
result.WriteString("\n")
return result.String()
}

View File

@ -1,773 +0,0 @@
// 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 x509util includes utility code for working with X.509
// certificates from the x509 package.
package x509util
import (
"bytes"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"encoding/base64"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"strconv"
ct "github.com/google/certificate-transparency-go"
"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/x509"
"github.com/google/certificate-transparency-go/x509/pkix"
)
// OIDForStandardExtension indicates whether oid identifies a standard extension.
// Standard extensions are listed in RFC 5280 (and other RFCs).
func OIDForStandardExtension(oid asn1.ObjectIdentifier) bool {
if oid.Equal(x509.OIDExtensionSubjectKeyId) ||
oid.Equal(x509.OIDExtensionKeyUsage) ||
oid.Equal(x509.OIDExtensionExtendedKeyUsage) ||
oid.Equal(x509.OIDExtensionAuthorityKeyId) ||
oid.Equal(x509.OIDExtensionBasicConstraints) ||
oid.Equal(x509.OIDExtensionSubjectAltName) ||
oid.Equal(x509.OIDExtensionCertificatePolicies) ||
oid.Equal(x509.OIDExtensionNameConstraints) ||
oid.Equal(x509.OIDExtensionCRLDistributionPoints) ||
oid.Equal(x509.OIDExtensionIssuerAltName) ||
oid.Equal(x509.OIDExtensionSubjectDirectoryAttributes) ||
oid.Equal(x509.OIDExtensionInhibitAnyPolicy) ||
oid.Equal(x509.OIDExtensionPolicyConstraints) ||
oid.Equal(x509.OIDExtensionPolicyMappings) ||
oid.Equal(x509.OIDExtensionFreshestCRL) ||
oid.Equal(x509.OIDExtensionSubjectInfoAccess) ||
oid.Equal(x509.OIDExtensionAuthorityInfoAccess) ||
oid.Equal(x509.OIDExtensionCTPoison) ||
oid.Equal(x509.OIDExtensionCTSCT) {
return true
}
return false
}
// OIDInExtensions checks whether the extension identified by oid is present in extensions
// and returns how many times it occurs together with an indication of whether any of them
// are marked critical.
func OIDInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) (int, bool) {
count := 0
critical := false
for _, ext := range extensions {
if ext.Id.Equal(oid) {
count++
if ext.Critical {
critical = true
}
}
}
return count, critical
}
// String formatting for various X.509/ASN.1 types
func bitStringToString(b asn1.BitString) string {
result := hex.EncodeToString(b.Bytes)
bitsLeft := b.BitLength % 8
if bitsLeft != 0 {
result += " (" + strconv.Itoa(8-bitsLeft) + " unused bits)"
}
return result
}
func publicKeyAlgorithmToString(algo x509.PublicKeyAlgorithm) string {
// Use OpenSSL-compatible strings for the algorithms.
switch algo {
case x509.RSA:
return "rsaEncryption"
case x509.DSA:
return "dsaEncryption"
case x509.ECDSA:
return "id-ecPublicKey"
default:
return strconv.Itoa(int(algo))
}
}
// appendHexData adds a hex dump of binary data to buf, with line breaks
// after each set of count bytes, and with each new line prefixed with the
// given prefix.
func appendHexData(buf *bytes.Buffer, data []byte, count int, prefix string) {
for ii, byte := range data {
if ii%count == 0 {
if ii > 0 {
buf.WriteString("\n")
}
buf.WriteString(prefix)
}
buf.WriteString(fmt.Sprintf("%02x:", byte))
}
}
func curveOIDToString(oid asn1.ObjectIdentifier) (t string, bitlen int) {
switch {
case oid.Equal(x509.OIDNamedCurveP224):
return "secp224r1", 224
case oid.Equal(x509.OIDNamedCurveP256):
return "prime256v1", 256
case oid.Equal(x509.OIDNamedCurveP384):
return "secp384r1", 384
case oid.Equal(x509.OIDNamedCurveP521):
return "secp521r1", 521
}
return fmt.Sprintf("%v", oid), -1
}
func publicKeyToString(algo x509.PublicKeyAlgorithm, pub interface{}) string {
var buf bytes.Buffer
switch pub := pub.(type) {
case *rsa.PublicKey:
bitlen := pub.N.BitLen()
buf.WriteString(fmt.Sprintf(" Public Key: (%d bit)\n", bitlen))
buf.WriteString(" Modulus:\n")
data := pub.N.Bytes()
appendHexData(&buf, data, 15, " ")
buf.WriteString("\n")
buf.WriteString(fmt.Sprintf(" Exponent: %d (0x%x)", pub.E, pub.E))
case *dsa.PublicKey:
buf.WriteString(" pub:\n")
appendHexData(&buf, pub.Y.Bytes(), 15, " ")
buf.WriteString("\n")
buf.WriteString(" P:\n")
appendHexData(&buf, pub.P.Bytes(), 15, " ")
buf.WriteString("\n")
buf.WriteString(" Q:\n")
appendHexData(&buf, pub.Q.Bytes(), 15, " ")
buf.WriteString("\n")
buf.WriteString(" G:\n")
appendHexData(&buf, pub.G.Bytes(), 15, " ")
case *ecdsa.PublicKey:
data := elliptic.Marshal(pub.Curve, pub.X, pub.Y)
oid, ok := x509.OIDFromNamedCurve(pub.Curve)
if !ok {
return " <unsupported elliptic curve>"
}
oidname, bitlen := curveOIDToString(oid)
buf.WriteString(fmt.Sprintf(" Public Key: (%d bit)\n", bitlen))
buf.WriteString(" pub:\n")
appendHexData(&buf, data, 15, " ")
buf.WriteString("\n")
buf.WriteString(fmt.Sprintf(" ASN1 OID: %s", oidname))
default:
buf.WriteString(fmt.Sprintf("%v", pub))
}
return buf.String()
}
func commaAppend(buf *bytes.Buffer, s string) {
if buf.Len() > 0 {
buf.WriteString(", ")
}
buf.WriteString(s)
}
func keyUsageToString(k x509.KeyUsage) string {
var buf bytes.Buffer
if k&x509.KeyUsageDigitalSignature != 0 {
commaAppend(&buf, "Digital Signature")
}
if k&x509.KeyUsageContentCommitment != 0 {
commaAppend(&buf, "Content Commitment")
}
if k&x509.KeyUsageKeyEncipherment != 0 {
commaAppend(&buf, "Key Encipherment")
}
if k&x509.KeyUsageDataEncipherment != 0 {
commaAppend(&buf, "Data Encipherment")
}
if k&x509.KeyUsageKeyAgreement != 0 {
commaAppend(&buf, "Key Agreement")
}
if k&x509.KeyUsageCertSign != 0 {
commaAppend(&buf, "Certificate Signing")
}
if k&x509.KeyUsageCRLSign != 0 {
commaAppend(&buf, "CRL Signing")
}
if k&x509.KeyUsageEncipherOnly != 0 {
commaAppend(&buf, "Encipher Only")
}
if k&x509.KeyUsageDecipherOnly != 0 {
commaAppend(&buf, "Decipher Only")
}
return buf.String()
}
func extKeyUsageToString(u x509.ExtKeyUsage) string {
switch u {
case x509.ExtKeyUsageAny:
return "Any"
case x509.ExtKeyUsageServerAuth:
return "TLS Web server authentication"
case x509.ExtKeyUsageClientAuth:
return "TLS Web client authentication"
case x509.ExtKeyUsageCodeSigning:
return "Signing of executable code"
case x509.ExtKeyUsageEmailProtection:
return "Email protection"
case x509.ExtKeyUsageIPSECEndSystem:
return "IPSEC end system"
case x509.ExtKeyUsageIPSECTunnel:
return "IPSEC tunnel"
case x509.ExtKeyUsageIPSECUser:
return "IPSEC user"
case x509.ExtKeyUsageTimeStamping:
return "Time stamping"
case x509.ExtKeyUsageOCSPSigning:
return "OCSP signing"
case x509.ExtKeyUsageMicrosoftServerGatedCrypto:
return "Microsoft server gated cryptography"
case x509.ExtKeyUsageNetscapeServerGatedCrypto:
return "Netscape server gated cryptography"
case x509.ExtKeyUsageCertificateTransparency:
return "Certificate transparency"
default:
return "Unknown"
}
}
func attributeOIDToString(oid asn1.ObjectIdentifier) string {
switch {
case oid.Equal(pkix.OIDCountry):
return "Country"
case oid.Equal(pkix.OIDOrganization):
return "Organization"
case oid.Equal(pkix.OIDOrganizationalUnit):
return "OrganizationalUnit"
case oid.Equal(pkix.OIDCommonName):
return "CommonName"
case oid.Equal(pkix.OIDSerialNumber):
return "SerialNumber"
case oid.Equal(pkix.OIDLocality):
return "Locality"
case oid.Equal(pkix.OIDProvince):
return "Province"
case oid.Equal(pkix.OIDStreetAddress):
return "StreetAddress"
case oid.Equal(pkix.OIDPostalCode):
return "PostalCode"
case oid.Equal(pkix.OIDPseudonym):
return "Pseudonym"
case oid.Equal(pkix.OIDTitle):
return "Title"
case oid.Equal(pkix.OIDDnQualifier):
return "DnQualifier"
case oid.Equal(pkix.OIDName):
return "Name"
case oid.Equal(pkix.OIDSurname):
return "Surname"
case oid.Equal(pkix.OIDGivenName):
return "GivenName"
case oid.Equal(pkix.OIDInitials):
return "Initials"
case oid.Equal(pkix.OIDGenerationQualifier):
return "GenerationQualifier"
default:
return oid.String()
}
}
// NameToString creates a string description of a pkix.Name object.
func NameToString(name pkix.Name) string {
var result bytes.Buffer
addSingle := func(prefix, item string) {
if len(item) == 0 {
return
}
commaAppend(&result, prefix)
result.WriteString(item)
}
addList := func(prefix string, items []string) {
for _, item := range items {
addSingle(prefix, item)
}
}
addList("C=", name.Country)
addList("O=", name.Organization)
addList("OU=", name.OrganizationalUnit)
addList("L=", name.Locality)
addList("ST=", name.Province)
addList("streetAddress=", name.StreetAddress)
addList("postalCode=", name.PostalCode)
addSingle("serialNumber=", name.SerialNumber)
addSingle("CN=", name.CommonName)
for _, atv := range name.Names {
value, ok := atv.Value.(string)
if !ok {
continue
}
t := atv.Type
// All of the defined attribute OIDs are of the form 2.5.4.N, and OIDAttribute is
// the 2.5.4 prefix ('id-at' in RFC 5280).
if len(t) == 4 && t[0] == pkix.OIDAttribute[0] && t[1] == pkix.OIDAttribute[1] && t[2] == pkix.OIDAttribute[2] {
// OID is 'id-at N', so check the final value to figure out which attribute.
switch t[3] {
case pkix.OIDCommonName[3], pkix.OIDSerialNumber[3], pkix.OIDCountry[3], pkix.OIDLocality[3], pkix.OIDProvince[3],
pkix.OIDStreetAddress[3], pkix.OIDOrganization[3], pkix.OIDOrganizationalUnit[3], pkix.OIDPostalCode[3]:
continue // covered by explicit fields
case pkix.OIDPseudonym[3]:
addSingle("pseudonym=", value)
continue
case pkix.OIDTitle[3]:
addSingle("title=", value)
continue
case pkix.OIDDnQualifier[3]:
addSingle("dnQualifier=", value)
continue
case pkix.OIDName[3]:
addSingle("name=", value)
continue
case pkix.OIDSurname[3]:
addSingle("surname=", value)
continue
case pkix.OIDGivenName[3]:
addSingle("givenName=", value)
continue
case pkix.OIDInitials[3]:
addSingle("initials=", value)
continue
case pkix.OIDGenerationQualifier[3]:
addSingle("generationQualifier=", value)
continue
}
}
addSingle(t.String()+"=", value)
}
return result.String()
}
// OtherNameToString creates a string description of an x509.OtherName object.
func OtherNameToString(other x509.OtherName) string {
return fmt.Sprintf("%v=%v", other.TypeID, hex.EncodeToString(other.Value.Bytes))
}
// GeneralNamesToString creates a string description of an x509.GeneralNames object.
func GeneralNamesToString(gname *x509.GeneralNames) string {
var buf bytes.Buffer
for _, name := range gname.DNSNames {
commaAppend(&buf, "DNS:"+name)
}
for _, email := range gname.EmailAddresses {
commaAppend(&buf, "email:"+email)
}
for _, name := range gname.DirectoryNames {
commaAppend(&buf, "DirName:"+NameToString(name))
}
for _, uri := range gname.URIs {
commaAppend(&buf, "URI:"+uri)
}
for _, ip := range gname.IPNets {
if ip.Mask == nil {
commaAppend(&buf, "IP Address:"+ip.IP.String())
} else {
commaAppend(&buf, "IP Address:"+ip.IP.String()+"/"+ip.Mask.String())
}
}
for _, id := range gname.RegisteredIDs {
commaAppend(&buf, "Registered ID:"+id.String())
}
for _, other := range gname.OtherNames {
commaAppend(&buf, "othername:"+OtherNameToString(other))
}
return buf.String()
}
// CertificateToString generates a string describing the given certificate.
// The output roughly resembles that from openssl x509 -text.
func CertificateToString(cert *x509.Certificate) string {
var result bytes.Buffer
result.WriteString(fmt.Sprintf("Certificate:\n"))
result.WriteString(fmt.Sprintf(" Data:\n"))
result.WriteString(fmt.Sprintf(" Version: %d (%#x)\n", cert.Version, cert.Version-1))
result.WriteString(fmt.Sprintf(" Serial Number: %d (%#[1]x)\n", cert.SerialNumber))
result.WriteString(fmt.Sprintf(" Signature Algorithm: %v\n", cert.SignatureAlgorithm))
result.WriteString(fmt.Sprintf(" Issuer: %v\n", NameToString(cert.Issuer)))
result.WriteString(fmt.Sprintf(" Validity:\n"))
result.WriteString(fmt.Sprintf(" Not Before: %v\n", cert.NotBefore))
result.WriteString(fmt.Sprintf(" Not After : %v\n", cert.NotAfter))
result.WriteString(fmt.Sprintf(" Subject: %v\n", NameToString(cert.Subject)))
result.WriteString(fmt.Sprintf(" Subject Public Key Info:\n"))
result.WriteString(fmt.Sprintf(" Public Key Algorithm: %v\n", publicKeyAlgorithmToString(cert.PublicKeyAlgorithm)))
result.WriteString(fmt.Sprintf("%v\n", publicKeyToString(cert.PublicKeyAlgorithm, cert.PublicKey)))
if len(cert.Extensions) > 0 {
result.WriteString(fmt.Sprintf(" X509v3 extensions:\n"))
}
// First display the extensions that are already cracked out
showAuthKeyID(&result, cert)
showSubjectKeyID(&result, cert)
showKeyUsage(&result, cert)
showExtendedKeyUsage(&result, cert)
showBasicConstraints(&result, cert)
showSubjectAltName(&result, cert)
showNameConstraints(&result, cert)
showCertPolicies(&result, cert)
showCRLDPs(&result, cert)
showAuthInfoAccess(&result, cert)
showCTPoison(&result, cert)
showCTSCT(&result, cert)
showCTLogSTHInfo(&result, cert)
showUnhandledExtensions(&result, cert)
showSignature(&result, cert)
return result.String()
}
func showCritical(result *bytes.Buffer, critical bool) {
if critical {
result.WriteString(" critical")
}
result.WriteString("\n")
}
func showAuthKeyID(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionAuthorityKeyId, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Authority Key Identifier:"))
showCritical(result, critical)
result.WriteString(fmt.Sprintf(" keyid:%v\n", hex.EncodeToString(cert.AuthorityKeyId)))
}
}
func showSubjectKeyID(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionSubjectKeyId, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Subject Key Identifier:"))
showCritical(result, critical)
result.WriteString(fmt.Sprintf(" keyid:%v\n", hex.EncodeToString(cert.SubjectKeyId)))
}
}
func showKeyUsage(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionKeyUsage, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Key Usage:"))
showCritical(result, critical)
result.WriteString(fmt.Sprintf(" %v\n", keyUsageToString(cert.KeyUsage)))
}
}
func showExtendedKeyUsage(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionExtendedKeyUsage, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Extended Key Usage:"))
showCritical(result, critical)
var usages bytes.Buffer
for _, usage := range cert.ExtKeyUsage {
commaAppend(&usages, extKeyUsageToString(usage))
}
for _, oid := range cert.UnknownExtKeyUsage {
commaAppend(&usages, oid.String())
}
result.WriteString(fmt.Sprintf(" %v\n", usages.String()))
}
}
func showBasicConstraints(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionBasicConstraints, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Basic Constraints:"))
showCritical(result, critical)
result.WriteString(fmt.Sprintf(" CA:%t", cert.IsCA))
if cert.MaxPathLen > 0 || cert.MaxPathLenZero {
result.WriteString(fmt.Sprintf(", pathlen:%d", cert.MaxPathLen))
}
result.WriteString(fmt.Sprintf("\n"))
}
}
func showSubjectAltName(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionSubjectAltName, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Subject Alternative Name:"))
showCritical(result, critical)
var buf bytes.Buffer
for _, name := range cert.DNSNames {
commaAppend(&buf, "DNS:"+name)
}
for _, email := range cert.EmailAddresses {
commaAppend(&buf, "email:"+email)
}
for _, ip := range cert.IPAddresses {
commaAppend(&buf, "IP Address:"+ip.String())
}
result.WriteString(fmt.Sprintf(" %v\n", buf.String()))
// TODO(drysdale): include other name forms
}
}
func showNameConstraints(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionNameConstraints, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Name Constraints:"))
showCritical(result, critical)
if len(cert.PermittedDNSDomains) > 0 {
result.WriteString(fmt.Sprintf(" Permitted:\n"))
var buf bytes.Buffer
for _, name := range cert.PermittedDNSDomains {
commaAppend(&buf, "DNS:"+name)
}
result.WriteString(fmt.Sprintf(" %v\n", buf.String()))
}
// TODO(drysdale): include other name forms
}
}
func showCertPolicies(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionCertificatePolicies, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 Certificate Policies:"))
showCritical(result, critical)
for _, oid := range cert.PolicyIdentifiers {
result.WriteString(fmt.Sprintf(" Policy: %v\n", oid.String()))
// TODO(drysdale): Display any qualifiers associated with the policy
}
}
}
func showCRLDPs(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionCRLDistributionPoints, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" X509v3 CRL Distribution Points:"))
showCritical(result, critical)
result.WriteString(fmt.Sprintf(" Full Name:\n"))
var buf bytes.Buffer
for _, pt := range cert.CRLDistributionPoints {
commaAppend(&buf, "URI:"+pt)
}
result.WriteString(fmt.Sprintf(" %v\n", buf.String()))
// TODO(drysdale): Display other GeneralNames types, plus issuer/reasons/relative-name
}
}
func showAuthInfoAccess(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionAuthorityInfoAccess, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" Authority Information Access:"))
showCritical(result, critical)
var issuerBuf bytes.Buffer
for _, issuer := range cert.IssuingCertificateURL {
commaAppend(&issuerBuf, "URI:"+issuer)
}
if issuerBuf.Len() > 0 {
result.WriteString(fmt.Sprintf(" CA Issuers - %v\n", issuerBuf.String()))
}
var ocspBuf bytes.Buffer
for _, ocsp := range cert.OCSPServer {
commaAppend(&ocspBuf, "URI:"+ocsp)
}
if ocspBuf.Len() > 0 {
result.WriteString(fmt.Sprintf(" OCSP - %v\n", ocspBuf.String()))
}
// TODO(drysdale): Display other GeneralNames types
}
}
func showCTPoison(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionCTPoison, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" RFC6962 Pre-Certificate Poison:"))
showCritical(result, critical)
result.WriteString(" .....\n")
}
}
func showCTSCT(result *bytes.Buffer, cert *x509.Certificate) {
count, critical := OIDInExtensions(x509.OIDExtensionCTSCT, cert.Extensions)
if count > 0 {
result.WriteString(fmt.Sprintf(" RFC6962 Certificate Transparency SCT:"))
showCritical(result, critical)
for i, sctData := range cert.SCTList.SCTList {
result.WriteString(fmt.Sprintf(" SCT [%d]:\n", i))
var sct ct.SignedCertificateTimestamp
_, err := tls.Unmarshal(sctData.Val, &sct)
if err != nil {
appendHexData(result, sctData.Val, 16, " ")
result.WriteString("\n")
continue
}
result.WriteString(fmt.Sprintf(" Version: %d\n", sct.SCTVersion))
result.WriteString(fmt.Sprintf(" LogID: %s\n", base64.StdEncoding.EncodeToString(sct.LogID.KeyID[:])))
result.WriteString(fmt.Sprintf(" Timestamp: %d\n", sct.Timestamp))
result.WriteString(fmt.Sprintf(" Signature: %s\n", sct.Signature.Algorithm))
result.WriteString(fmt.Sprintf(" Signature:\n"))
appendHexData(result, sct.Signature.Signature, 16, " ")
result.WriteString("\n")
}
}
}
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) {
for _, ext := range cert.Extensions {
// Skip extensions that are already cracked out
if oidAlreadyPrinted(ext.Id) {
continue
}
result.WriteString(fmt.Sprintf(" %v:", ext.Id))
showCritical(result, ext.Critical)
appendHexData(result, ext.Value, 16, " ")
result.WriteString("\n")
}
}
func showSignature(result *bytes.Buffer, cert *x509.Certificate) {
result.WriteString(fmt.Sprintf(" Signature Algorithm: %v\n", cert.SignatureAlgorithm))
appendHexData(result, cert.Signature, 18, " ")
result.WriteString("\n")
}
// TODO(drysdale): remove this once all standard OIDs are parsed and printed.
func oidAlreadyPrinted(oid asn1.ObjectIdentifier) bool {
if oid.Equal(x509.OIDExtensionSubjectKeyId) ||
oid.Equal(x509.OIDExtensionKeyUsage) ||
oid.Equal(x509.OIDExtensionExtendedKeyUsage) ||
oid.Equal(x509.OIDExtensionAuthorityKeyId) ||
oid.Equal(x509.OIDExtensionBasicConstraints) ||
oid.Equal(x509.OIDExtensionSubjectAltName) ||
oid.Equal(x509.OIDExtensionCertificatePolicies) ||
oid.Equal(x509.OIDExtensionNameConstraints) ||
oid.Equal(x509.OIDExtensionCRLDistributionPoints) ||
oid.Equal(x509.OIDExtensionAuthorityInfoAccess) ||
oid.Equal(x509.OIDExtensionCTPoison) ||
oid.Equal(x509.OIDExtensionCTSCT) ||
oid.Equal(x509ext.OIDExtensionCTSTH) {
return true
}
return false
}
// CertificateFromPEM takes a certificate in PEM format and returns the
// corresponding x509.Certificate object.
func CertificateFromPEM(pemBytes []byte) (*x509.Certificate, error) {
block, rest := pem.Decode(pemBytes)
if len(rest) != 0 {
return nil, errors.New("trailing data found after PEM block")
}
if block == nil {
return nil, errors.New("PEM block is nil")
}
if block.Type != "CERTIFICATE" {
return nil, errors.New("PEM block is not a CERTIFICATE")
}
return x509.ParseCertificate(block.Bytes)
}
// CertificatesFromPEM parses one or more certificates from the given PEM data.
// The PEM certificates must be concatenated. This function can be used for
// parsing PEM-formatted certificate chains, but does not verify that the
// resulting chain is a valid certificate chain.
func CertificatesFromPEM(pemBytes []byte) ([]*x509.Certificate, error) {
var chain []*x509.Certificate
for {
var block *pem.Block
block, pemBytes = pem.Decode(pemBytes)
if block == nil {
return chain, nil
}
if block.Type != "CERTIFICATE" {
return nil, fmt.Errorf("PEM block is not a CERTIFICATE")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, errors.New("failed to parse certificate")
}
chain = append(chain, cert)
}
}
// ParseSCTsFromSCTList parses each of the SCTs contained within an SCT list.
func ParseSCTsFromSCTList(sctList *x509.SignedCertificateTimestampList) ([]*ct.SignedCertificateTimestamp, error) {
var scts []*ct.SignedCertificateTimestamp
for i, data := range sctList.SCTList {
sct, err := ExtractSCT(&data)
if err != nil {
return nil, fmt.Errorf("error extracting SCT number %d: %s", i, err)
}
scts = append(scts, sct)
}
return scts, nil
}
// ExtractSCT deserializes an SCT from a TLS-encoded SCT.
func ExtractSCT(sctData *x509.SerializedSCT) (*ct.SignedCertificateTimestamp, error) {
if sctData == nil {
return nil, errors.New("SCT is nil")
}
var sct ct.SignedCertificateTimestamp
if rest, err := tls.Unmarshal(sctData.Val, &sct); err != nil {
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
}
var pemCertificatePrefix = []byte("-----BEGIN CERTIFICATE")
// ParseSCTsFromCertificate parses any SCTs that are embedded in the
// certificate provided. The certificate bytes provided can be either DER or
// PEM, provided the PEM data starts with the PEM block marker (i.e. has no
// leading text).
func ParseSCTsFromCertificate(certBytes []byte) ([]*ct.SignedCertificateTimestamp, error) {
var cert *x509.Certificate
var err error
if bytes.HasPrefix(certBytes, pemCertificatePrefix) {
cert, err = CertificateFromPEM(certBytes)
} else {
cert, err = x509.ParseCertificate(certBytes)
}
if err != nil {
return nil, fmt.Errorf("failed to parse certificate: %s", err)
}
return ParseSCTsFromSCTList(&cert.SCTList)
}