blob: 3ff0b7d428671f8de97ffa59bf585ab8c0ddbf65 [file] [log] [blame]
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package x509
import (
"fmt"
"net"
"github.com/google/certificate-transparency-go/asn1"
"github.com/google/certificate-transparency-go/x509/pkix"
)
const (
// GeneralName tag values from RFC 5280, 4.2.1.6
tagOtherName = 0
tagRFC822Name = 1
tagDNSName = 2
tagX400Address = 3
tagDirectoryName = 4
tagEDIPartyName = 5
tagURI = 6
tagIPAddress = 7
tagRegisteredID = 8
)
// OtherName describes a name related to a certificate which is not in one
// of the standard name formats. RFC 5280, 4.2.1.6:
// OtherName ::= SEQUENCE {
// type-id OBJECT IDENTIFIER,
// value [0] EXPLICIT ANY DEFINED BY type-id }
type OtherName struct {
TypeID asn1.ObjectIdentifier
Value asn1.RawValue
}
// GeneralNames holds a collection of names related to a certificate.
type GeneralNames struct {
DNSNames []string
EmailAddresses []string
DirectoryNames []pkix.Name
URIs []string
IPNets []net.IPNet
RegisteredIDs []asn1.ObjectIdentifier
OtherNames []OtherName
}
// Len returns the total number of names in a GeneralNames object.
func (gn GeneralNames) Len() int {
return (len(gn.DNSNames) + len(gn.EmailAddresses) + len(gn.DirectoryNames) +
len(gn.URIs) + len(gn.IPNets) + len(gn.RegisteredIDs) + len(gn.OtherNames))
}
// Empty indicates whether a GeneralNames object is empty.
func (gn GeneralNames) Empty() bool {
return gn.Len() == 0
}
func parseGeneralNames(value []byte, gname *GeneralNames) error {
// RFC 5280, 4.2.1.6
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
//
// GeneralName ::= CHOICE {
// otherName [0] OtherName,
// rfc822Name [1] IA5String,
// dNSName [2] IA5String,
// x400Address [3] ORAddress,
// directoryName [4] Name,
// ediPartyName [5] EDIPartyName,
// uniformResourceIdentifier [6] IA5String,
// iPAddress [7] OCTET STRING,
// registeredID [8] OBJECT IDENTIFIER }
var seq asn1.RawValue
var rest []byte
if rest, err := asn1.Unmarshal(value, &seq); err != nil {
return fmt.Errorf("x509: failed to parse GeneralNames: %v", err)
} else if len(rest) != 0 {
return fmt.Errorf("x509: trailing data after GeneralNames")
}
if !seq.IsCompound || seq.Tag != asn1.TagSequence || seq.Class != asn1.ClassUniversal {
return fmt.Errorf("x509: failed to parse GeneralNames sequence, tag %+v", seq)
}
rest = seq.Bytes
for len(rest) > 0 {
var err error
rest, err = parseGeneralName(rest, gname, false)
if err != nil {
return fmt.Errorf("x509: failed to parse GeneralName: %v", err)
}
}
return nil
}
func parseGeneralName(data []byte, gname *GeneralNames, withMask bool) ([]byte, error) {
var v asn1.RawValue
var rest []byte
var err error
rest, err = asn1.Unmarshal(data, &v)
if err != nil {
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames: %v", err)
}
switch v.Tag {
case tagOtherName:
if !v.IsCompound {
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.otherName: not compound")
}
var other OtherName
v.FullBytes = append([]byte{}, v.FullBytes...)
v.FullBytes[0] = asn1.TagSequence | 0x20
_, err = asn1.Unmarshal(v.FullBytes, &other)
if err != nil {
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.otherName: %v", err)
}
gname.OtherNames = append(gname.OtherNames, other)
case tagRFC822Name:
gname.EmailAddresses = append(gname.EmailAddresses, string(v.Bytes))
case tagDNSName:
dns := string(v.Bytes)
gname.DNSNames = append(gname.DNSNames, dns)
case tagDirectoryName:
var rdnSeq pkix.RDNSequence
if _, err := asn1.Unmarshal(v.Bytes, &rdnSeq); err != nil {
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.directoryName: %v", err)
}
var dirName pkix.Name
dirName.FillFromRDNSequence(&rdnSeq)
gname.DirectoryNames = append(gname.DirectoryNames, dirName)
case tagURI:
gname.URIs = append(gname.URIs, string(v.Bytes))
case tagIPAddress:
vlen := len(v.Bytes)
if withMask {
switch vlen {
case (2 * net.IPv4len), (2 * net.IPv6len):
ipNet := net.IPNet{IP: v.Bytes[0 : vlen/2], Mask: v.Bytes[vlen/2:]}
gname.IPNets = append(gname.IPNets, ipNet)
default:
return nil, fmt.Errorf("x509: invalid IP/mask length %d in GeneralNames.iPAddress", vlen)
}
} else {
switch vlen {
case net.IPv4len, net.IPv6len:
ipNet := net.IPNet{IP: v.Bytes}
gname.IPNets = append(gname.IPNets, ipNet)
default:
return nil, fmt.Errorf("x509: invalid IP length %d in GeneralNames.iPAddress", vlen)
}
}
case tagRegisteredID:
var oid asn1.ObjectIdentifier
v.FullBytes = append([]byte{}, v.FullBytes...)
v.FullBytes[0] = asn1.TagOID
_, err = asn1.Unmarshal(v.FullBytes, &oid)
if err != nil {
return nil, fmt.Errorf("x509: failed to unmarshal GeneralNames.registeredID: %v", err)
}
gname.RegisteredIDs = append(gname.RegisteredIDs, oid)
default:
return nil, fmt.Errorf("x509: failed to unmarshal GeneralName: unknown tag %d", v.Tag)
}
return rest, nil
}