243 lines
8.4 KiB
Go
243 lines
8.4 KiB
Go
|
// 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)
|
||
|
}
|