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