feat(dir2config)

This commit is contained in:
Mikaël Cluseau
2018-12-11 00:44:05 +11:00
parent 26b6efd54c
commit 7435995592
106 changed files with 5352 additions and 4052 deletions

View File

@ -14,9 +14,22 @@ env:
matrix:
fast_finish: true
addons:
apt:
sources:
- mysql-5.7-trusty
packages:
- mysql-server
- mysql-client
services:
- docker
before_install:
- sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('') where User='root'; update user set plugin='mysql_native_password';FLUSH PRIVILEGES;"
- sudo mysql_upgrade
- sudo service mysql restart
install:
- mkdir ../protoc
- |

View File

@ -1,5 +1,19 @@
# CERTIFICATE-TRANSPARENCY-GO Changelog
## v1.0.20 - Minimal Gossip / Go 1.11 Fix / Utility Improvements
Published 2018-07-05 09:21:34 +0000 UTC
Enhancements have been made to various utilities including `scanner`, `sctcheck`, `loglist` and `x509util`.
The `allow_verification_with_non_compliant_keys` flag has been removed from `signatures.go`.
An implementation of Gossip has been added. See the `gossip/minimal` package for more information.
An X.509 compatibility issue for Go 1.11 has been fixed. This should be backwards compatible with 1.10.
Commit [37a384cd035e722ea46e55029093e26687138edf](https://api.github.com/repos/google/certificate-transparency-go/commits/37a384cd035e722ea46e55029093e26687138edf) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.20)
## v1.0.19 - CTFE User Quota
Published 2018-06-01 13:51:52 +0000 UTC
@ -12,10 +26,10 @@ Commit [8736a411b4ff214ea20687e46c2b67d66ebd83fc](https://api.github.com/repos/g
Published 2018-06-01 14:28:20 +0000 UTC
Work on a log migration tool (Migrillian) is in progress. This is not yet ready for production use but will provide features for mirroring and migrating logs.
The `RequestLog` API allows for logging of SCTs when they are issued by CTFE.
Work on a log migration tool (Migrillian) is in progress. This is not yet ready for production use but will provide features for mirroring and migrating logs.
The `RequestLog` API allows for logging of SCTs when they are issued by CTFE.
The CT Go client now supports `GetEntryAndProof`. Utilities have been switched over to use the `glog` package.
Commit [77abf2dac5410a62c04ac1c662c6d0fa54afc2dc](https://api.github.com/repos/google/certificate-transparency-go/commits/77abf2dac5410a62c04ac1c662c6d0fa54afc2dc) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.18)
@ -24,12 +38,12 @@ Commit [77abf2dac5410a62c04ac1c662c6d0fa54afc2dc](https://api.github.com/repos/g
Published 2018-06-01 14:25:16 +0000 UTC
Now uses Merkle Tree verification from Trillian.
The CT server now supports CORS.
Request tracing added using OpenCensus. For GCE / K8 it just requires the flag to be enabled to export traces to Stackdriver. Other environments may differ.
Now uses Merkle Tree verification from Trillian.
The CT server now supports CORS.
Request tracing added using OpenCensus. For GCE / K8 it just requires the flag to be enabled to export traces to Stackdriver. Other environments may differ.
A demo script was added that goes through setting up a simple deployment suitable for development / demo purposes. This may be useful for those new to the project.
Commit [3c3d22ce946447d047a03228ebb4a41e3e4eb15b](https://api.github.com/repos/google/certificate-transparency-go/commits/3c3d22ce946447d047a03228ebb4a41e3e4eb15b) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.17)
@ -38,8 +52,8 @@ Commit [3c3d22ce946447d047a03228ebb4a41e3e4eb15b](https://api.github.com/repos/g
Published 2018-06-01 14:22:23 +0000 UTC
An integration test was added that goes through a create / drain queue / freeze lifecycle for a log.
An integration test was added that goes through a create / drain queue / freeze lifecycle for a log.
Changes to `x509` were merged from Go 1.10.1.
Commit [a72423d09b410b80673fd1135ba1022d04bac6cd](https://api.github.com/repos/google/certificate-transparency-go/commits/a72423d09b410b80673fd1135ba1022d04bac6cd) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.16)
@ -48,10 +62,10 @@ Commit [a72423d09b410b80673fd1135ba1022d04bac6cd](https://api.github.com/repos/g
Published 2018-06-01 14:20:32 +0000 UTC
Facilities were added to the `x509` package to control whether verification checks are applied.
Log server requests are now balanced using `gRPClb`.
Facilities were added to the `x509` package to control whether verification checks are applied.
Log server requests are now balanced using `gRPClb`.
For Kubernetes, metrics can be published to Stackdriver monitoring.
Commit [684d6eee6092774e54d301ccad0ed61bc8d010c1](https://api.github.com/repos/google/certificate-transparency-go/commits/684d6eee6092774e54d301ccad0ed61bc8d010c1) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.15)
@ -60,8 +74,8 @@ Commit [684d6eee6092774e54d301ccad0ed61bc8d010c1](https://api.github.com/repos/g
Published 2018-06-01 14:15:37 +0000 UTC
Support for SQLlite was removed. This motivation was ongoing test flakiness caused by multi-user access. This database may work for an embedded scenario but is not suitable for use in a server environment.
Support for SQLlite was removed. This motivation was ongoing test flakiness caused by multi-user access. This database may work for an embedded scenario but is not suitable for use in a server environment.
A `LeafHashForLeaf` client API was added and is now used by the CT client and integration tests.
Commit [698cd6a661196db4b2e71437422178ffe8705006](https://api.github.com/repos/google/certificate-transparency-go/commits/698cd6a661196db4b2e71437422178ffe8705006) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.14)
@ -70,10 +84,10 @@ Commit [698cd6a661196db4b2e71437422178ffe8705006](https://api.github.com/repos/g
Published 2018-06-01 14:15:21 +0000 UTC
Some of our custom crypto package that were wrapping calls to the standard package have been removed and the base features used directly.
Updates were made to GCE ingress and health checks.
Some of our custom crypto package that were wrapping calls to the standard package have been removed and the base features used directly.
Updates were made to GCE ingress and health checks.
The log list utility can verify signatures.
Commit [480c3654a70c5383b9543ec784203030aedbd3a5](https://api.github.com/repos/google/certificate-transparency-go/commits/480c3654a70c5383b9543ec784203030aedbd3a5) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.13)
@ -82,10 +96,10 @@ Commit [480c3654a70c5383b9543ec784203030aedbd3a5](https://api.github.com/repos/g
Published 2018-06-01 14:13:42 +0000 UTC
The CT client can now use a JSON loglist to find logs.
CTFE had a fix applied for preissued precerts.
The CT client can now use a JSON loglist to find logs.
CTFE had a fix applied for preissued precerts.
A DNS client was added and CT client was extended to support DNS retrieval.
Commit [74c06c95e0b304a050a1c33764c8a01d653a16e3](https://api.github.com/repos/google/certificate-transparency-go/commits/74c06c95e0b304a050a1c33764c8a01d653a16e3) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.12)
@ -102,8 +116,8 @@ Commit [0856acca7e0ab7f082ae83a1fbb5d21160962efc](https://api.github.com/repos/g
Published 2018-06-01 14:09:47 +0000 UTC
The CT client was using the wrong protobuffer library package. To guard against this in future a check has been added to our lint config.
The CT client was using the wrong protobuffer library package. To guard against this in future a check has been added to our lint config.
The `x509` and `asn1` packages have had upstream fixes applied from Go 1.10rc1.
Commit [1bec4527572c443752ad4f2830bef88be0533236](https://api.github.com/repos/google/certificate-transparency-go/commits/1bec4527572c443752ad4f2830bef88be0533236) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.10)
@ -112,10 +126,10 @@ Commit [1bec4527572c443752ad4f2830bef88be0533236](https://api.github.com/repos/g
Published 2018-06-01 14:11:13 +0000 UTC
The `scanner` utility now displays throughput stats.
Build instructions and README files were updated.
The `scanner` utility now displays throughput stats.
Build instructions and README files were updated.
The `certcheck` utility can be told to ignore unknown critical X.509 extensions.
Commit [c06833528d04a94eed0c775104d1107bab9ae17c](https://api.github.com/repos/google/certificate-transparency-go/commits/c06833528d04a94eed0c775104d1107bab9ae17c) Download [zip](https://api.github.com/repos/google/certificate-transparency-go/zipball/v1.0.9)

View File

@ -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

View File

@ -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 {

View File

@ -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).

View File

@ -121,7 +121,7 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
}
cert, err := ParseCertificate(block.Bytes)
if err != nil {
if IsFatal(err) {
continue
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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")

View File

@ -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)