From b982d7859dfae611b7043b657e2e4a538c8e6cc3 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sun, 20 Oct 2019 15:25:36 +0200 Subject: [PATCH] bump google/certificate-transparency-go v1.0.21 full diff: https://github.com/google/certificate-transparency-go/compare/v1.0.20...v1.0.21 - CTFE no longer prints certificate chains as long byte strings in messages when handler errors occur. This was obscuring the reason for the failure and wasn't particularly useful. - CTFE now has a global log URL path prefix flag and a configuration proto for a log specific path. The latter should help for various migration strategies if existing C++ server logs are going to be converted to run on the new code. - More progress has been made on log mirroring. We believe that it's now at the point where testing can begin. - The certcheck and ct_hammer utilities have received more enhancements. - x509 and x509util now support Subject Information Access and additional exten- sions for RPKI / RFC - scanner / fixchain and some other command line utilities now have better handling of non-fatal errors. Signed-off-by: Sebastiaan van Stijn --- vendor.conf | 4 +- .../client/getentries.go | 2 +- .../serialization.go | 100 +++++--- .../certificate-transparency-go/types.go | 19 ++ .../x509/cert_pool.go | 2 +- .../x509/curves.go | 37 +++ .../x509/revoked.go | 9 +- .../certificate-transparency-go/x509/rpki.go | 242 ++++++++++++++++++ .../certificate-transparency-go/x509/sec1.go | 5 +- .../certificate-transparency-go/x509/x509.go | 212 ++++++++++++--- 10 files changed, 562 insertions(+), 70 deletions(-) create mode 100644 vendor/github.com/google/certificate-transparency-go/x509/curves.go create mode 100644 vendor/github.com/google/certificate-transparency-go/x509/rpki.go diff --git a/vendor.conf b/vendor.conf index 994bd66643..19b4daaad9 100644 --- a/vendor.conf +++ b/vendor.conf @@ -8,7 +8,7 @@ # In >=1.11, those errors were brought back but the string had changed again. # After updating GRPC, if integration test failures occur, verify that the # string matching there is correct. -google.golang.org/grpc v1.23.0 +google.golang.org/grpc v1.23.0 github.com/gogo/protobuf b03c65ea87cdc3521ede29f62fe3ce239267c1bc # v1.3.2 github.com/golang/protobuf 84668698ea25b64748563aa20726db66a6b8d299 # v1.3.5 github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c # v1.0.1 @@ -54,7 +54,7 @@ github.com/beorn7/perks 37c8de3658fcb183f997c4e13e83 github.com/cloudflare/cfssl 5d63dbd981b5c408effbb58c442d54761ff94fbd # 1.3.2 github.com/dustin/go-humanize 9f541cc9db5d55bce703bd99987c9d5cb8eea45e # v1.0.0 github.com/fernet/fernet-go 9eac43b88a5efb8651d24de9b68e87567e029736 -github.com/google/certificate-transparency-go 37a384cd035e722ea46e55029093e26687138edf # v1.0.20 +github.com/google/certificate-transparency-go 3629d6846518309d22c16fee15d1007262a459d2 # v1.0.21 github.com/hashicorp/go-immutable-radix 826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad github.com/hashicorp/golang-lru 7f827b33c0f158ec5dfbba01bb0b14a4541fd81d # v0.5.3 diff --git a/vendor/github.com/google/certificate-transparency-go/client/getentries.go b/vendor/github.com/google/certificate-transparency-go/client/getentries.go index e2cde55c22..1194c51609 100644 --- a/vendor/github.com/google/certificate-transparency-go/client/getentries.go +++ b/vendor/github.com/google/certificate-transparency-go/client/getentries.go @@ -66,7 +66,7 @@ func (c *LogClient) GetEntries(ctx context.Context, start, end int64) ([]ct.LogE for i, entry := range resp.Entries { index := start + int64(i) logEntry, err := ct.LogEntryFromLeaf(index, &entry) - if _, ok := err.(x509.NonFatalErrors); !ok && err != nil { + if x509.IsFatal(err) { return nil, err } entries[i] = *logEntry diff --git a/vendor/github.com/google/certificate-transparency-go/serialization.go b/vendor/github.com/google/certificate-transparency-go/serialization.go index 39053ecd30..a1b558d14b 100644 --- a/vendor/github.com/google/certificate-transparency-go/serialization.go +++ b/vendor/github.com/google/certificate-transparency-go/serialization.go @@ -128,7 +128,7 @@ func MerkleTreeLeafFromRawChain(rawChain []ASN1Cert, etype LogEntryType, timesta chain := make([]*x509.Certificate, count) for i := range chain { cert, err := x509.ParseCertificate(rawChain[i].Data) - if err != nil { + if x509.IsFatal(err) { return nil, fmt.Errorf("failed to parse chain[%d] cert: %v", i, err) } chain[i] = cert @@ -248,60 +248,96 @@ func IsPreIssuer(issuer *x509.Certificate) bool { return false } -// LogEntryFromLeaf converts a LeafEntry object (which has the raw leaf data after JSON parsing) -// into a LogEntry object (which includes x509.Certificate objects, after TLS and ASN.1 parsing). -// Note that this function may return a valid LogEntry object and a non-nil error value, when -// the error indicates a non-fatal parsing error (of type x509.NonFatalErrors). -func LogEntryFromLeaf(index int64, leafEntry *LeafEntry) (*LogEntry, error) { - var leaf MerkleTreeLeaf - if rest, err := tls.Unmarshal(leafEntry.LeafInput, &leaf); err != nil { - return nil, fmt.Errorf("failed to unmarshal MerkleTreeLeaf for index %d: %v", index, err) +// RawLogEntryFromLeaf converts a LeafEntry object (which has the raw leaf data +// after JSON parsing) into a RawLogEntry object (i.e. a TLS-parsed structure). +func RawLogEntryFromLeaf(index int64, entry *LeafEntry) (*RawLogEntry, error) { + ret := RawLogEntry{Index: index} + if rest, err := tls.Unmarshal(entry.LeafInput, &ret.Leaf); err != nil { + return nil, fmt.Errorf("failed to unmarshal MerkleTreeLeaf: %v", err) } else if len(rest) > 0 { - return nil, fmt.Errorf("trailing data (%d bytes) after MerkleTreeLeaf for index %d", len(rest), index) + return nil, fmt.Errorf("MerkleTreeLeaf: trailing data %d bytes", len(rest)) } - var err error - entry := LogEntry{Index: index, Leaf: leaf} - switch leaf.TimestampedEntry.EntryType { + switch eType := ret.Leaf.TimestampedEntry.EntryType; eType { case X509LogEntryType: var certChain CertificateChain - if rest, err := tls.Unmarshal(leafEntry.ExtraData, &certChain); err != nil { - return nil, fmt.Errorf("failed to unmarshal ExtraData for index %d: %v", index, err) + if rest, err := tls.Unmarshal(entry.ExtraData, &certChain); err != nil { + return nil, fmt.Errorf("failed to unmarshal CertificateChain: %v", err) } else if len(rest) > 0 { - return nil, fmt.Errorf("trailing data (%d bytes) after CertificateChain for index %d", len(rest), index) - } - entry.Chain = certChain.Entries - entry.X509Cert, err = leaf.X509Certificate() - if _, ok := err.(x509.NonFatalErrors); !ok && err != nil { - return nil, fmt.Errorf("failed to parse certificate in MerkleTreeLeaf for index %d: %v", index, err) + return nil, fmt.Errorf("CertificateChain: trailing data %d bytes", len(rest)) } + ret.Cert = *ret.Leaf.TimestampedEntry.X509Entry + ret.Chain = certChain.Entries case PrecertLogEntryType: var precertChain PrecertChainEntry - if rest, err := tls.Unmarshal(leafEntry.ExtraData, &precertChain); err != nil { - return nil, fmt.Errorf("failed to unmarshal PrecertChainEntry for index %d: %v", index, err) + if rest, err := tls.Unmarshal(entry.ExtraData, &precertChain); err != nil { + return nil, fmt.Errorf("failed to unmarshal PrecertChainEntry: %v", err) } else if len(rest) > 0 { - return nil, fmt.Errorf("trailing data (%d bytes) after PrecertChainEntry for index %d", len(rest), index) + return nil, fmt.Errorf("PrecertChainEntry: trailing data %d bytes", len(rest)) } - entry.Chain = precertChain.CertificateChain + ret.Cert = precertChain.PreCertificate + ret.Chain = precertChain.CertificateChain + + default: + // TODO(pavelkalinnikov): Section 4.6 of RFC6962 implies that unknown types + // are not errors. We should revisit how we process this case. + return nil, fmt.Errorf("unknown entry type: %v", eType) + } + + return &ret, nil +} + +// ToLogEntry converts RawLogEntry to a LogEntry, which includes an x509-parsed +// (pre-)certificate. +// +// Note that this function may return a valid LogEntry object and a non-nil +// error value, when the error indicates a non-fatal parsing error. +func (rle *RawLogEntry) ToLogEntry() (*LogEntry, error) { + var err error + entry := LogEntry{Index: rle.Index, Leaf: rle.Leaf, Chain: rle.Chain} + + switch eType := rle.Leaf.TimestampedEntry.EntryType; eType { + case X509LogEntryType: + entry.X509Cert, err = rle.Leaf.X509Certificate() + if x509.IsFatal(err) { + return nil, fmt.Errorf("failed to parse certificate: %v", err) + } + + case PrecertLogEntryType: var tbsCert *x509.Certificate - tbsCert, err = leaf.Precertificate() - if _, ok := err.(x509.NonFatalErrors); !ok && err != nil { - return nil, fmt.Errorf("failed to parse precertificate in MerkleTreeLeaf for index %d: %v", index, err) + tbsCert, err = rle.Leaf.Precertificate() + if x509.IsFatal(err) { + return nil, fmt.Errorf("failed to parse precertificate: %v", err) } entry.Precert = &Precertificate{ - Submitted: precertChain.PreCertificate, - IssuerKeyHash: leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash, + Submitted: rle.Cert, + IssuerKeyHash: rle.Leaf.TimestampedEntry.PrecertEntry.IssuerKeyHash, TBSCertificate: tbsCert, } default: - return nil, fmt.Errorf("saw unknown entry type at index %d: %v", index, leaf.TimestampedEntry.EntryType) + return nil, fmt.Errorf("unknown entry type: %v", eType) } - // err may hold a x509.NonFatalErrors object. + + // err may be non-nil for a non-fatal error. return &entry, err } +// LogEntryFromLeaf converts a LeafEntry object (which has the raw leaf data +// after JSON parsing) into a LogEntry object (which includes x509.Certificate +// objects, after TLS and ASN.1 parsing). +// +// Note that this function may return a valid LogEntry object and a non-nil +// error value, when the error indicates a non-fatal parsing error. +func LogEntryFromLeaf(index int64, leaf *LeafEntry) (*LogEntry, error) { + rle, err := RawLogEntryFromLeaf(index, leaf) + if err != nil { + return nil, err + } + return rle.ToLogEntry() +} + // TimestampToTime converts a timestamp in the style of RFC 6962 (milliseconds // since UNIX epoch) to a Go Time. func TimestampToTime(ts uint64) time.Time { diff --git a/vendor/github.com/google/certificate-transparency-go/types.go b/vendor/github.com/google/certificate-transparency-go/types.go index bcdd7e9222..156b5c64de 100644 --- a/vendor/github.com/google/certificate-transparency-go/types.go +++ b/vendor/github.com/google/certificate-transparency-go/types.go @@ -199,6 +199,25 @@ func (d *DigitallySigned) UnmarshalJSON(b []byte) error { return d.FromBase64String(content) } +// RawLogEntry represents the (TLS-parsed) contents of an entry in a CT log. +type RawLogEntry struct { + // Index is a position of the entry in the log. + Index int64 + // Leaf is a parsed Merkle leaf hash input. + Leaf MerkleTreeLeaf + // Cert is: + // - A certificate if Leaf.TimestampedEntry.EntryType is X509LogEntryType. + // - A precertificate if Leaf.TimestampedEntry.EntryType is + // PrecertLogEntryType, in the form of a DER-encoded Certificate as + // originally added (which includes the poison extension and a signature + // generated over the pre-cert by the pre-cert issuer). + // - Empty otherwise. + Cert ASN1Cert + // Chain is the issuing certificate chain starting with the issuer of Cert, + // or an empty slice if Cert is empty. + Chain []ASN1Cert +} + // LogEntry represents the (parsed) contents of an entry in a CT log. This is described // in section 3.1, but note that this structure does *not* match the TLS structure // defined there (the TLS structure is never used directly in RFC6962). diff --git a/vendor/github.com/google/certificate-transparency-go/x509/cert_pool.go b/vendor/github.com/google/certificate-transparency-go/x509/cert_pool.go index 71ffbdf0e0..1196479a0c 100644 --- a/vendor/github.com/google/certificate-transparency-go/x509/cert_pool.go +++ b/vendor/github.com/google/certificate-transparency-go/x509/cert_pool.go @@ -121,7 +121,7 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { } cert, err := ParseCertificate(block.Bytes) - if err != nil { + if IsFatal(err) { continue } diff --git a/vendor/github.com/google/certificate-transparency-go/x509/curves.go b/vendor/github.com/google/certificate-transparency-go/x509/curves.go new file mode 100644 index 0000000000..0e2778cb35 --- /dev/null +++ b/vendor/github.com/google/certificate-transparency-go/x509/curves.go @@ -0,0 +1,37 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +import ( + "crypto/elliptic" + "math/big" + "sync" +) + +// This file holds ECC curves that are not supported by the main Go crypto/elliptic +// library, but which have been observed in certificates in the wild. + +var initonce sync.Once +var p192r1 *elliptic.CurveParams + +func initAllCurves() { + initSECP192R1() +} + +func initSECP192R1() { + // See SEC-2, section 2.2.2 + p192r1 = &elliptic.CurveParams{Name: "P-192"} + p192r1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16) + p192r1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", 16) + p192r1.B, _ = new(big.Int).SetString("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", 16) + p192r1.Gx, _ = new(big.Int).SetString("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", 16) + p192r1.Gy, _ = new(big.Int).SetString("07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", 16) + p192r1.BitSize = 192 +} + +func secp192r1() elliptic.Curve { + initonce.Do(initAllCurves) + return p192r1 +} diff --git a/vendor/github.com/google/certificate-transparency-go/x509/revoked.go b/vendor/github.com/google/certificate-transparency-go/x509/revoked.go index e704441639..fde74b942a 100644 --- a/vendor/github.com/google/certificate-transparency-go/x509/revoked.go +++ b/vendor/github.com/google/certificate-transparency-go/x509/revoked.go @@ -14,12 +14,15 @@ import ( "github.com/google/certificate-transparency-go/x509/pkix" ) +// OID values for CRL extensions (TBSCertList.Extensions), RFC 5280 s5.2. var ( - // OID values for CRL extensions (TBSCertList.Extensions), RFC 5280 s5.2. OIDExtensionCRLNumber = asn1.ObjectIdentifier{2, 5, 29, 20} OIDExtensionDeltaCRLIndicator = asn1.ObjectIdentifier{2, 5, 29, 27} OIDExtensionIssuingDistributionPoint = asn1.ObjectIdentifier{2, 5, 29, 28} - // OID values for CRL entry extensions (RevokedCertificate.Extensions), RFC 5280 s5.3 +) + +// OID values for CRL entry extensions (RevokedCertificate.Extensions), RFC 5280 s5.3 +var ( OIDExtensionCRLReasons = asn1.ObjectIdentifier{2, 5, 29, 21} OIDExtensionInvalidityDate = asn1.ObjectIdentifier{2, 5, 29, 24} OIDExtensionCertificateIssuer = asn1.ObjectIdentifier{2, 5, 29, 29} @@ -238,7 +241,7 @@ func ParseCertificateListDER(derBytes []byte) (*CertificateList, error) { } case e.Id.Equal(OIDExtensionAuthorityInfoAccess): // RFC 5280 s5.2.7 - var aia []authorityInfoAccess + var aia []accessDescription if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil { errs.AddID(ErrInvalidCertListAuthInfoAccess, err) } else if len(rest) != 0 { diff --git a/vendor/github.com/google/certificate-transparency-go/x509/rpki.go b/vendor/github.com/google/certificate-transparency-go/x509/rpki.go new file mode 100644 index 0000000000..520d6dc3ab --- /dev/null +++ b/vendor/github.com/google/certificate-transparency-go/x509/rpki.go @@ -0,0 +1,242 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + + "github.com/google/certificate-transparency-go/asn1" +) + +// IPAddressPrefix describes an IP address prefix as an ASN.1 bit string, +// where the BitLength field holds the prefix length. +type IPAddressPrefix asn1.BitString + +// IPAddressRange describes an (inclusive) IP address range. +type IPAddressRange struct { + Min IPAddressPrefix + Max IPAddressPrefix +} + +// Most relevant values for AFI from: +// http://www.iana.org/assignments/address-family-numbers. +const ( + IPv4AddressFamilyIndicator = uint16(1) + IPv6AddressFamilyIndicator = uint16(2) +) + +// IPAddressFamilyBlocks describes a set of ranges of IP addresses. +type IPAddressFamilyBlocks struct { + // AFI holds an address family indicator from + // http://www.iana.org/assignments/address-family-numbers. + AFI uint16 + // SAFI holds a subsequent address family indicator from + // http://www.iana.org/assignments/safi-namespace. + SAFI byte + // InheritFromIssuer indicates that the set of addresses should + // be taken from the issuer's certificate. + InheritFromIssuer bool + // AddressPrefixes holds prefixes if InheritFromIssuer is false. + AddressPrefixes []IPAddressPrefix + // AddressRanges holds ranges if InheritFromIssuer is false. + AddressRanges []IPAddressRange +} + +// Internal types for asn1 unmarshalling. +type ipAddressFamily struct { + AddressFamily []byte // 2-byte AFI plus optional 1 byte SAFI + Choice asn1.RawValue +} + +// Internally, use raw asn1.BitString rather than the IPAddressPrefix +// type alias (so that asn1.Unmarshal() decodes properly). +type ipAddressRange struct { + Min asn1.BitString + Max asn1.BitString +} + +func parseRPKIAddrBlocks(data []byte, nfe *NonFatalErrors) []*IPAddressFamilyBlocks { + // RFC 3779 2.2.3 + // IPAddrBlocks ::= SEQUENCE OF IPAddressFamily + // + // IPAddressFamily ::= SEQUENCE { -- AFI & optional SAFI -- + // addressFamily OCTET STRING (SIZE (2..3)), + // ipAddressChoice IPAddressChoice } + // + // IPAddressChoice ::= CHOICE { + // inherit NULL, -- inherit from issuer -- + // addressesOrRanges SEQUENCE OF IPAddressOrRange } + // + // IPAddressOrRange ::= CHOICE { + // addressPrefix IPAddress, + // addressRange IPAddressRange } + // + // IPAddressRange ::= SEQUENCE { + // min IPAddress, + // max IPAddress } + // + // IPAddress ::= BIT STRING + + var addrBlocks []ipAddressFamily + if rest, err := asn1.Unmarshal(data, &addrBlocks); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks extension: %v", err)) + return nil + } else if len(rest) != 0 { + nfe.AddError(errors.New("trailing data after ipAddrBlocks extension")) + return nil + } + + var results []*IPAddressFamilyBlocks + for i, block := range addrBlocks { + var fam IPAddressFamilyBlocks + if l := len(block.AddressFamily); l < 2 || l > 3 { + nfe.AddError(fmt.Errorf("invalid address family length (%d) for ipAddrBlock.addressFamily", l)) + continue + } + fam.AFI = binary.BigEndian.Uint16(block.AddressFamily[0:2]) + if len(block.AddressFamily) > 2 { + fam.SAFI = block.AddressFamily[2] + } + // IPAddressChoice is an ASN.1 CHOICE where the chosen alternative is indicated by (implicit) + // tagging of the alternatives -- here, either NULL or SEQUENCE OF. + if bytes.Equal(block.Choice.FullBytes, asn1.NullBytes) { + fam.InheritFromIssuer = true + results = append(results, &fam) + continue + } + + var addrRanges []asn1.RawValue + if _, err := asn1.Unmarshal(block.Choice.FullBytes, &addrRanges); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges: %v", i, err)) + continue + } + for j, ar := range addrRanges { + // Each IPAddressOrRange is a CHOICE where the alternatives have distinct (implicit) + // tags -- here, either BIT STRING or SEQUENCE. + switch ar.Tag { + case asn1.TagBitString: + // BIT STRING for single prefix IPAddress + var val asn1.BitString + if _, err := asn1.Unmarshal(ar.FullBytes, &val); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges[%d].addressPrefix: %v", i, j, err)) + continue + } + fam.AddressPrefixes = append(fam.AddressPrefixes, IPAddressPrefix(val)) + + case asn1.TagSequence: + var val ipAddressRange + if _, err := asn1.Unmarshal(ar.FullBytes, &val); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges[%d].addressRange: %v", i, j, err)) + continue + } + fam.AddressRanges = append(fam.AddressRanges, IPAddressRange{Min: IPAddressPrefix(val.Min), Max: IPAddressPrefix(val.Max)}) + + default: + nfe.AddError(fmt.Errorf("unexpected ASN.1 type in ipAddrBlocks[%d].ipAddressChoice.addressesOrRanges[%d]: %+v", i, j, ar)) + } + } + results = append(results, &fam) + } + return results +} + +// ASIDRange describes an inclusive range of AS Identifiers (AS numbers or routing +// domain identifiers). +type ASIDRange struct { + Min int + Max int +} + +// ASIdentifiers describes a collection of AS Identifiers (AS numbers or routing +// domain identifiers). +type ASIdentifiers struct { + // InheritFromIssuer indicates that the set of AS identifiers should + // be taken from the issuer's certificate. + InheritFromIssuer bool + // ASIDs holds AS identifiers if InheritFromIssuer is false. + ASIDs []int + // ASIDs holds AS identifier ranges (inclusive) if InheritFromIssuer is false. + ASIDRanges []ASIDRange +} + +type asIdentifiers struct { + ASNum asn1.RawValue `asn1:"optional,tag:0"` + RDI asn1.RawValue `asn1:"optional,tag:1"` +} + +func parseASIDChoice(val asn1.RawValue, nfe *NonFatalErrors) *ASIdentifiers { + // RFC 3779 2.3.2 + // ASIdentifierChoice ::= CHOICE { + // inherit NULL, -- inherit from issuer -- + // asIdsOrRanges SEQUENCE OF ASIdOrRange } + // ASIdOrRange ::= CHOICE { + // id ASId, + // range ASRange } + // ASRange ::= SEQUENCE { + // min ASId, + // max ASId } + // ASId ::= INTEGER + if len(val.FullBytes) == 0 { // OPTIONAL + return nil + } + // ASIdentifierChoice is an ASN.1 CHOICE where the chosen alternative is indicated by (implicit) + // tagging of the alternatives -- here, either NULL or SEQUENCE OF. + if bytes.Equal(val.Bytes, asn1.NullBytes) { + return &ASIdentifiers{InheritFromIssuer: true} + } + var ids []asn1.RawValue + if rest, err := asn1.Unmarshal(val.Bytes, &ids); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers.asIdsOrRanges: %v", err)) + return nil + } else if len(rest) != 0 { + nfe.AddError(errors.New("trailing data after ASIdentifiers.asIdsOrRanges")) + return nil + } + var asID ASIdentifiers + for i, id := range ids { + // Each ASIdOrRange is a CHOICE where the alternatives have distinct (implicit) + // tags -- here, either INTEGER or SEQUENCE. + switch id.Tag { + case asn1.TagInteger: + var val int + if _, err := asn1.Unmarshal(id.FullBytes, &val); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers.asIdsOrRanges[%d].id: %v", i, err)) + continue + } + asID.ASIDs = append(asID.ASIDs, val) + + case asn1.TagSequence: + var val ASIDRange + if _, err := asn1.Unmarshal(id.FullBytes, &val); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers.asIdsOrRanges[%d].range: %v", i, err)) + continue + } + asID.ASIDRanges = append(asID.ASIDRanges, val) + + default: + nfe.AddError(fmt.Errorf("unexpected value in ASIdentifiers.asIdsOrRanges[%d]: %+v", i, id)) + } + } + return &asID +} + +func parseRPKIASIdentifiers(data []byte, nfe *NonFatalErrors) (*ASIdentifiers, *ASIdentifiers) { + // RFC 3779 2.3.2 + // ASIdentifiers ::= SEQUENCE { + // asnum [0] EXPLICIT ASIdentifierChoice OPTIONAL, + // rdi [1] EXPLICIT ASIdentifierChoice OPTIONAL} + var asIDs asIdentifiers + if rest, err := asn1.Unmarshal(data, &asIDs); err != nil { + nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal ASIdentifiers extension: %v", err)) + return nil, nil + } else if len(rest) != 0 { + nfe.AddError(errors.New("trailing data after ASIdentifiers extension")) + return nil, nil + } + return parseASIDChoice(asIDs.ASNum, nfe), parseASIDChoice(asIDs.RDI, nfe) +} diff --git a/vendor/github.com/google/certificate-transparency-go/x509/sec1.go b/vendor/github.com/google/certificate-transparency-go/x509/sec1.go index ae4f81e560..7c51e15c44 100644 --- a/vendor/github.com/google/certificate-transparency-go/x509/sec1.go +++ b/vendor/github.com/google/certificate-transparency-go/x509/sec1.go @@ -72,11 +72,12 @@ func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *e return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version) } + var nfe NonFatalErrors var curve elliptic.Curve if namedCurveOID != nil { - curve = namedCurveFromOID(*namedCurveOID) + curve = namedCurveFromOID(*namedCurveOID, &nfe) } else { - curve = namedCurveFromOID(privKey.NamedCurveOID) + curve = namedCurveFromOID(privKey.NamedCurveOID, &nfe) } if curve == nil { return nil, errors.New("x509: unknown elliptic curve") diff --git a/vendor/github.com/google/certificate-transparency-go/x509/x509.go b/vendor/github.com/google/certificate-transparency-go/x509/x509.go index 23f2a6a228..387bc432bf 100644 --- a/vendor/github.com/google/certificate-transparency-go/x509/x509.go +++ b/vendor/github.com/google/certificate-transparency-go/x509/x509.go @@ -8,9 +8,39 @@ // can be used to override the system default locations for the SSL certificate // file and SSL certificate files directory, respectively. // -// This is a fork of the go library crypto/x509 package, it's more relaxed -// about certificates that it'll accept, and exports the TBSCertificate -// structure. +// This is a fork of the Go library crypto/x509 package, primarily adapted for +// use with Certificate Transparency. Main areas of difference are: +// +// - Life as a fork: +// - Rename OS-specific cgo code so it doesn't clash with main Go library. +// - Use local library imports (asn1, pkix) throughout. +// - Add version-specific wrappers for Go version-incompatible code (in +// nilref_*_darwin.go, ptr_*_windows.go). +// - Laxer certificate parsing: +// - Add options to disable various validation checks (times, EKUs etc). +// - Use NonFatalErrors type for some errors and continue parsing; this +// can be checked with IsFatal(err). +// - Support for short bitlength ECDSA curves (in curves.go). +// - Certificate Transparency specific function: +// - Parsing and marshaling of SCTList extension. +// - RemoveSCTList() function for rebuilding CT leaf entry. +// - Pre-certificate processing (RemoveCTPoison(), BuildPrecertTBS(), +// ParseTBSCertificate(), IsPrecertificate()). +// - Revocation list processing: +// - Detailed CRL parsing (in revoked.go) +// - Detailed error recording mechanism (in error.go, errors.go) +// - Factor out parseDistributionPoints() for reuse. +// - Factor out and generalize GeneralNames parsing (in names.go) +// - Fix CRL commenting. +// - RPKI support: +// - Support for SubjectInfoAccess extension +// - Support for RFC3779 extensions (in rpki.go) +// - General improvements: +// - Export and use OID values throughout. +// - Export OIDFromNamedCurve(). +// - Export SignatureAlgorithmFromAI(). +// - Add OID value to UnhandledCriticalExtension error. +// - Minor typo/lint fixes. package x509 import ( @@ -69,7 +99,16 @@ func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { if algo == UnknownPublicKeyAlgorithm { return nil, errors.New("x509: unknown public key algorithm") } - return parsePublicKey(algo, &pki) + var nfe NonFatalErrors + pub, err = parsePublicKey(algo, &pki, &nfe) + if err != nil { + return pub, err + } + // Treat non-fatal errors as fatal for this entrypoint. + if len(nfe.Errors) > 0 { + return nil, nfe.Errors[0] + } + return pub, nil } func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { @@ -500,15 +539,21 @@ func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm // secp521r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 35 } // -// NB: secp256r1 is equivalent to prime256v1 +// secp192r1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) +// prime(1) 1 } +// +// NB: secp256r1 is equivalent to prime256v1, +// secp192r1 is equivalent to ansix9p192r and prime192v1 var ( OIDNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} OIDNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} OIDNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} OIDNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} + OIDNamedCurveP192 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 1} ) -func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { +func namedCurveFromOID(oid asn1.ObjectIdentifier, nfe *NonFatalErrors) elliptic.Curve { switch { case oid.Equal(OIDNamedCurveP224): return elliptic.P224() @@ -518,6 +563,9 @@ func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { return elliptic.P384() case oid.Equal(OIDNamedCurveP521): return elliptic.P521() + case oid.Equal(OIDNamedCurveP192): + nfe.AddError(errors.New("insecure curve (secp192r1) specified")) + return secp192r1() } return nil } @@ -534,6 +582,8 @@ func OIDFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { return OIDNamedCurveP384, true case elliptic.P521(): return OIDNamedCurveP521, true + case secp192r1(): + return OIDNamedCurveP192, true } return nil, false @@ -737,6 +787,10 @@ type Certificate struct { OCSPServer []string IssuingCertificateURL []string + // Subject Information Access + SubjectTimestamps []string + SubjectCARepositories []string + // Subject Alternate Name values. (Note that these values may not be valid // if invalid values were contained within a parsed certificate. For // example, an element of DNSNames may not be a valid DNS domain name.) @@ -761,6 +815,9 @@ type Certificate struct { PolicyIdentifiers []asn1.ObjectIdentifier + RPKIAddressRanges []*IPAddressFamilyBlocks + RPKIASNumbers, RPKIRoutingDomainIDs *ASIdentifiers + // Certificate Transparency SCT extension contents; this is a TLS-encoded // SignedCertificateTimestampList (RFC 6962 s3.3). RawSCT []byte @@ -1175,7 +1232,7 @@ const ( ) // RFC 5280, 4.2.2.1 -type authorityInfoAccess struct { +type accessDescription struct { Method asn1.ObjectIdentifier Location asn1.RawValue } @@ -1192,14 +1249,14 @@ type distributionPointName struct { RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` } -func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) { +func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo, nfe *NonFatalErrors) (interface{}, error) { asn1Data := keyData.PublicKey.RightAlign() switch algo { case RSA: // RSA public keys must have a NULL in the parameters // (https://tools.ietf.org/html/rfc3279#section-2.3.1). if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) { - return nil, errors.New("x509: RSA key missing NULL parameters") + nfe.AddError(errors.New("x509: RSA key missing NULL parameters")) } p := new(pkcs1PublicKey) @@ -1263,9 +1320,9 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ if len(rest) != 0 { return nil, errors.New("x509: trailing data after ECDSA parameters") } - namedCurve := namedCurveFromOID(*namedCurveOID) + namedCurve := namedCurveFromOID(*namedCurveOID, nfe) if namedCurve == nil { - return nil, errors.New("x509: unsupported elliptic curve") + return nil, fmt.Errorf("x509: unsupported elliptic curve %v", namedCurveOID) } x, y := elliptic.Unmarshal(namedCurve, asn1Data) if x == nil { @@ -1310,6 +1367,20 @@ func (e *NonFatalErrors) HasError() bool { return len(e.Errors) > 0 } +// IsFatal indicates whether an error is fatal. +func IsFatal(err error) bool { + if err == nil { + return false + } + if _, ok := err.(NonFatalErrors); ok { + return false + } + if errs, ok := err.(*Errors); ok { + return errs.Fatal() + } + return true +} + func parseDistributionPoints(data []byte, crldp *[]string) error { // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint // @@ -1622,7 +1693,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) var err error - out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey) + out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey, &nfe) if err != nil { return nil, err } @@ -1729,10 +1800,14 @@ func parseCertificate(in *certificate) (*Certificate, error) { // KeyPurposeId ::= OBJECT IDENTIFIER var keyUsage []asn1.ObjectIdentifier - if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil { - return nil, err - } else if len(rest) != 0 { - return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage") + if len(e.Value) == 0 { + nfe.AddError(errors.New("x509: empty ExtendedKeyUsage")) + } else { + if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage") + } } for _, u := range keyUsage { @@ -1772,12 +1847,15 @@ func parseCertificate(in *certificate) (*Certificate, error) { } } else if e.Id.Equal(OIDExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access - var aia []authorityInfoAccess + var aia []accessDescription if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil { return nil, err } else if len(rest) != 0 { return nil, errors.New("x509: trailing data after X.509 authority information") } + if len(aia) == 0 { + nfe.AddError(errors.New("x509: empty AuthorityInfoAccess extension")) + } for _, v := range aia { // GeneralName: uniformResourceIdentifier [6] IA5String @@ -1790,6 +1868,34 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes)) } } + } else if e.Id.Equal(OIDExtensionSubjectInfoAccess) { + // RFC 5280 4.2.2.2: Subject Information Access + var sia []accessDescription + if rest, err := asn1.Unmarshal(e.Value, &sia); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 subject information") + } + if len(sia) == 0 { + nfe.AddError(errors.New("x509: empty SubjectInfoAccess extension")) + } + + for _, v := range sia { + // TODO(drysdale): cope with non-URI types of GeneralName + // GeneralName: uniformResourceIdentifier [6] IA5String + if v.Location.Tag != 6 { + continue + } + if v.Method.Equal(OIDSubjectInfoAccessTimestamp) { + out.SubjectTimestamps = append(out.SubjectTimestamps, string(v.Location.Bytes)) + } else if v.Method.Equal(OIDSubjectInfoAccessCARepo) { + out.SubjectCARepositories = append(out.SubjectCARepositories, string(v.Location.Bytes)) + } + } + } else if e.Id.Equal(OIDExtensionIPPrefixList) { + out.RPKIAddressRanges = parseRPKIAddrBlocks(e.Value, &nfe) + } else if e.Id.Equal(OIDExtensionASList) { + out.RPKIASNumbers, out.RPKIRoutingDomainIDs = parseRPKIASIdentifiers(e.Value, &nfe) } else if e.Id.Equal(OIDExtensionCTSCT) { if rest, err := asn1.Unmarshal(e.Value, &out.RawSCT); err != nil { nfe.AddError(fmt.Errorf("failed to asn1.Unmarshal SCT list extension: %v", err)) @@ -1934,15 +2040,23 @@ var ( OIDExtensionAuthorityInfoAccess = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 1} OIDExtensionSubjectInfoAccess = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 11} + // OIDExtensionCTPoison is defined in RFC 6962 s3.1. OIDExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3} // OIDExtensionCTSCT is defined in RFC 6962 s3.3. OIDExtensionCTSCT = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2} + // OIDExtensionIPPrefixList is defined in RFC 3779 s2. + OIDExtensionIPPrefixList = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 7} + // OIDExtensionASList is defined in RFC 3779 s3. + OIDExtensionASList = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 8} ) var ( OIDAuthorityInfoAccessOCSP = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} OIDAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} + OIDSubjectInfoAccessTimestamp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 3} + OIDSubjectInfoAccessCARepo = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 5} + OIDAnyPolicy = asn1.ObjectIdentifier{2, 5, 29, 32, 0} ) // oidInExtensions returns whether an extension with the given oid exists in @@ -1991,7 +2105,7 @@ func isIA5String(s string) error { } func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) { - ret = make([]pkix.Extension, 11 /* maximum number of elements. */) + ret = make([]pkix.Extension, 12 /* maximum number of elements. */) n := 0 if template.KeyUsage != 0 && @@ -2076,15 +2190,15 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) && !oidInExtensions(OIDExtensionAuthorityInfoAccess, template.ExtraExtensions) { ret[n].Id = OIDExtensionAuthorityInfoAccess - var aiaValues []authorityInfoAccess + var aiaValues []accessDescription for _, name := range template.OCSPServer { - aiaValues = append(aiaValues, authorityInfoAccess{ + aiaValues = append(aiaValues, accessDescription{ Method: OIDAuthorityInfoAccessOCSP, Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(name)}, }) } for _, name := range template.IssuingCertificateURL { - aiaValues = append(aiaValues, authorityInfoAccess{ + aiaValues = append(aiaValues, accessDescription{ Method: OIDAuthorityInfoAccessIssuers, Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(name)}, }) @@ -2096,6 +2210,29 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId n++ } + if len(template.SubjectTimestamps) > 0 || len(template.SubjectCARepositories) > 0 && + !oidInExtensions(OIDExtensionSubjectInfoAccess, template.ExtraExtensions) { + ret[n].Id = OIDExtensionSubjectInfoAccess + var siaValues []accessDescription + for _, ts := range template.SubjectTimestamps { + siaValues = append(siaValues, accessDescription{ + Method: OIDSubjectInfoAccessTimestamp, + Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(ts)}, + }) + } + for _, repo := range template.SubjectCARepositories { + siaValues = append(siaValues, accessDescription{ + Method: OIDSubjectInfoAccessCARepo, + Location: asn1.RawValue{Tag: 6, Class: asn1.ClassContextSpecific, Bytes: []byte(repo)}, + }) + } + ret[n].Value, err = asn1.Marshal(siaValues) + if err != nil { + return + } + n++ + } + if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) && !oidInExtensions(OIDExtensionSubjectAltName, template.ExtraExtensions) { ret[n].Id = OIDExtensionSubjectAltName @@ -2349,12 +2486,25 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori var emptyASN1Subject = []byte{0x30, 0} // CreateCertificate creates a new X.509v3 certificate based on a template. -// The following members of template are used: AuthorityKeyId, -// BasicConstraintsValid, DNSNames, ExcludedDNSDomains, ExtKeyUsage, -// IsCA, KeyUsage, MaxPathLen, MaxPathLenZero, NotAfter, NotBefore, -// PermittedDNSDomains, PermittedDNSDomainsCritical, SerialNumber, -// SignatureAlgorithm, Subject, SubjectKeyId, UnknownExtKeyUsage, -// and RawSCT. +// The following members of template are used: +// - SerialNumber +// - Subject +// - NotBefore, NotAfter +// - SignatureAlgorithm +// - For extensions: +// - KeyUsage +// - ExtKeyUsage +// - BasicConstraintsValid, IsCA, MaxPathLen, MaxPathLenZero +// - SubjectKeyId +// - AuthorityKeyId +// - OCSPServer, IssuingCertificateURL +// - SubjectTimestamps, SubjectCARepositories +// - DNSNames, EmailAddresses, IPAddresses, URIs +// - PolicyIdentifiers +// - ExcludedDNSDomains, ExcludedIPRanges, ExcludedEmailAddresses, ExcludedURIDomains, PermittedDNSDomainsCritical, +// PermittedDNSDomains, PermittedIPRanges, PermittedEmailAddresses, PermittedURIDomains +// - CRLDistributionPoints +// - RawSCT, SCTList // // The certificate is signed by parent. If parent is equal to template then the // certificate is self-signed. The parameter pub is the public key of the @@ -2863,10 +3013,15 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error } var err error - out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey) + var nfe NonFatalErrors + out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey, &nfe) if err != nil { return nil, err } + // Treat non-fatal errors as fatal here. + if len(nfe.Errors) > 0 { + return nil, nfe.Errors[0] + } var subject pkix.RDNSequence if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil { @@ -2881,7 +3036,6 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error return nil, err } - var nfe NonFatalErrors for _, extension := range out.Extensions { if extension.Id.Equal(OIDExtensionSubjectAltName) { out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value, &nfe)