// Copyright 2021 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 ( cryptobyte_asn1 ) // isPrintable reports whether the given b is in the ASN.1 PrintableString set. // This is a simplified version of encoding/asn1.isPrintable. func ( byte) bool { return 'a' <= && <= 'z' || 'A' <= && <= 'Z' || '0' <= && <= '9' || '\'' <= && <= ')' || '+' <= && <= '/' || == ' ' || == ':' || == '=' || == '?' || // This is technically not allowed in a PrintableString. // However, x509 certificates with wildcard strings don't // always use the correct string type so we permit it. == '*' || // This is not technically allowed either. However, not // only is it relatively common, but there are also a // handful of CA certificates that contain it. At least // one of which will not expire until 2027. == '&' } // parseASN1String parses the ASN.1 string types T61String, PrintableString, // UTF8String, BMPString, IA5String, and NumericString. This is mostly copied // from the respective encoding/asn1.parse... methods, rather than just // increasing the API surface of that package. func ( cryptobyte_asn1.Tag, []byte) (string, error) { switch { case cryptobyte_asn1.T61String: return string(), nil case cryptobyte_asn1.PrintableString: for , := range { if !isPrintable() { return "", errors.New("invalid PrintableString") } } return string(), nil case cryptobyte_asn1.UTF8String: if !utf8.Valid() { return "", errors.New("invalid UTF-8 string") } return string(), nil case cryptobyte_asn1.Tag(asn1.TagBMPString): if len()%2 != 0 { return "", errors.New("invalid BMPString") } // Strip terminator if present. if := len(); >= 2 && [-1] == 0 && [-2] == 0 { = [:-2] } := make([]uint16, 0, len()/2) for len() > 0 { = append(, uint16([0])<<8+uint16([1])) = [2:] } return string(utf16.Decode()), nil case cryptobyte_asn1.IA5String: := string() if isIA5String() != nil { return "", errors.New("invalid IA5String") } return , nil case cryptobyte_asn1.Tag(asn1.TagNumericString): for , := range { if !('0' <= && <= '9' || == ' ') { return "", errors.New("invalid NumericString") } } return string(), nil } return "", fmt.Errorf("unsupported string type: %v", ) } // parseName parses a DER encoded Name as defined in RFC 5280. We may // want to export this function in the future for use in crypto/tls. func ( cryptobyte.String) (*pkix.RDNSequence, error) { if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RDNSequence") } var pkix.RDNSequence for !.Empty() { var pkix.RelativeDistinguishedNameSET var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SET) { return nil, errors.New("x509: invalid RDNSequence") } for !.Empty() { var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute") } var pkix.AttributeTypeAndValue if !.ReadASN1ObjectIdentifier(&.Type) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute type") } var cryptobyte.String var cryptobyte_asn1.Tag if !.ReadAnyASN1(&, &) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute value") } var error .Value, = parseASN1String(, ) if != nil { return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", ) } = append(, ) } = append(, ) } return &, nil } func ( cryptobyte.String) (pkix.AlgorithmIdentifier, error) { := pkix.AlgorithmIdentifier{} if !.ReadASN1ObjectIdentifier(&.Algorithm) { return , errors.New("x509: malformed OID") } if .Empty() { return , nil } var cryptobyte.String var cryptobyte_asn1.Tag if !.ReadAnyASN1Element(&, &) { return , errors.New("x509: malformed parameters") } .Parameters.Tag = int() .Parameters.FullBytes = return , nil } func ( cryptobyte.String) (time.Time, time.Time, error) { := func() (time.Time, error) { var time.Time switch { case .PeekASN1Tag(cryptobyte_asn1.UTCTime): // TODO(rolandshoemaker): once #45411 is fixed, the following code // should be replaced with a call to der.ReadASN1UTCTime. var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.UTCTime) { return , errors.New("x509: malformed UTCTime") } := string() := "0601021504Z0700" var error , = time.Parse(, ) if != nil { = "060102150405Z0700" , = time.Parse(, ) } if != nil { return , } if := .Format(); != { return , errors.New("x509: malformed UTCTime") } if .Year() >= 2050 { // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 = .AddDate(-100, 0, 0) } case .PeekASN1Tag(cryptobyte_asn1.GeneralizedTime): if !.ReadASN1GeneralizedTime(&) { return , errors.New("x509: malformed GeneralizedTime") } default: return , errors.New("x509: unsupported time format") } return , nil } , := () if != nil { return time.Time{}, time.Time{}, } , := () if != nil { return time.Time{}, time.Time{}, } return , , nil } func ( cryptobyte.String) (pkix.Extension, error) { var pkix.Extension if !.ReadASN1ObjectIdentifier(&.Id) { return , errors.New("x509: malformed extension OID field") } if .PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { if !.ReadASN1Boolean(&.Critical) { return , errors.New("x509: malformed extension critical field") } } var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.OCTET_STRING) { return , errors.New("x509: malformed extension value field") } .Value = return , nil } func ( PublicKeyAlgorithm, *publicKeyInfo) (any, error) { := cryptobyte.String(.PublicKey.RightAlign()) switch { case RSA: // RSA public keys must have a NULL in the parameters. // See RFC 3279, Section 2.3.1. if !bytes.Equal(.Algorithm.Parameters.FullBytes, asn1.NullBytes) { return nil, errors.New("x509: RSA key missing NULL parameters") } := &pkcs1PublicKey{N: new(big.Int)} if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RSA public key") } if !.ReadASN1Integer(.N) { return nil, errors.New("x509: invalid RSA modulus") } if !.ReadASN1Integer(&.E) { return nil, errors.New("x509: invalid RSA public exponent") } if .N.Sign() <= 0 { return nil, errors.New("x509: RSA modulus is not a positive number") } if .E <= 0 { return nil, errors.New("x509: RSA public exponent is not a positive number") } := &rsa.PublicKey{ E: .E, N: .N, } return , nil case ECDSA: := cryptobyte.String(.Algorithm.Parameters.FullBytes) := new(asn1.ObjectIdentifier) if !.ReadASN1ObjectIdentifier() { return nil, errors.New("x509: invalid ECDSA parameters") } := namedCurveFromOID(*) if == nil { return nil, errors.New("x509: unsupported elliptic curve") } , := elliptic.Unmarshal(, ) if == nil { return nil, errors.New("x509: failed to unmarshal elliptic curve point") } := &ecdsa.PublicKey{ Curve: , X: , Y: , } return , nil case Ed25519: // RFC 8410, Section 3 // > For all of the OIDs, the parameters MUST be absent. if len(.Algorithm.Parameters.FullBytes) != 0 { return nil, errors.New("x509: Ed25519 key encoded with illegal parameters") } if len() != ed25519.PublicKeySize { return nil, errors.New("x509: wrong Ed25519 public key size") } return ed25519.PublicKey(), nil case DSA: := new(big.Int) if !.ReadASN1Integer() { return nil, errors.New("x509: invalid DSA public key") } := &dsa.PublicKey{ Y: , Parameters: dsa.Parameters{ P: new(big.Int), Q: new(big.Int), G: new(big.Int), }, } := cryptobyte.String(.Algorithm.Parameters.FullBytes) if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) || !.ReadASN1Integer(.Parameters.P) || !.ReadASN1Integer(.Parameters.Q) || !.ReadASN1Integer(.Parameters.G) { return nil, errors.New("x509: invalid DSA parameters") } if .Y.Sign() <= 0 || .Parameters.P.Sign() <= 0 || .Parameters.Q.Sign() <= 0 || .Parameters.G.Sign() <= 0 { return nil, errors.New("x509: zero or negative DSA parameter") } return , nil default: return nil, nil } } func ( cryptobyte.String) (KeyUsage, error) { var asn1.BitString if !.ReadASN1BitString(&) { return 0, errors.New("x509: invalid key usage") } var int for := 0; < 9; ++ { if .At() != 0 { |= 1 << uint() } } return KeyUsage(), nil } func ( cryptobyte.String) (bool, int, error) { var bool if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return false, 0, errors.New("x509: invalid basic constraints a") } if .PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { if !.ReadASN1Boolean(&) { return false, 0, errors.New("x509: invalid basic constraints b") } } := -1 if !.Empty() && .PeekASN1Tag(cryptobyte_asn1.INTEGER) { if !.ReadASN1Integer(&) { return false, 0, errors.New("x509: invalid basic constraints c") } } // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) return , , nil } func ( cryptobyte.String, func( int, []byte) error) error { if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid subject alternative names") } for !.Empty() { var cryptobyte.String var cryptobyte_asn1.Tag if !.ReadAnyASN1(&, &) { return errors.New("x509: invalid subject alternative name") } if := (int(^0x80), ); != nil { return } } return nil } func ( cryptobyte.String) (, []string, []net.IP, []*url.URL, error) { = forEachSAN(, func( int, []byte) error { switch { case nameTypeEmail: := string() if := isIA5String(); != nil { return errors.New("x509: SAN rfc822Name is malformed") } = append(, ) case nameTypeDNS: := string() if := isIA5String(); != nil { return errors.New("x509: SAN dNSName is malformed") } = append(, string()) case nameTypeURI: := string() if := isIA5String(); != nil { return errors.New("x509: SAN uniformResourceIdentifier is malformed") } , := url.Parse() if != nil { return fmt.Errorf("x509: cannot parse URI %q: %s", , ) } if len(.Host) > 0 { if , := domainToReverseLabels(.Host); ! { return fmt.Errorf("x509: cannot parse URI %q: invalid domain", ) } } = append(, ) case nameTypeIP: switch len() { case net.IPv4len, net.IPv6len: = append(, ) default: return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len())) } } return nil }) return } func ( cryptobyte.String) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) { var []ExtKeyUsage var []asn1.ObjectIdentifier if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, nil, errors.New("x509: invalid extended key usages") } for !.Empty() { var asn1.ObjectIdentifier if !.ReadASN1ObjectIdentifier(&) { return nil, nil, errors.New("x509: invalid extended key usages") } if , := extKeyUsageFromOID(); { = append(, ) } else { = append(, ) } } return , , nil } func ( cryptobyte.String) ([]asn1.ObjectIdentifier, error) { var []asn1.ObjectIdentifier if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid certificate policies") } for !.Empty() { var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid certificate policies") } var asn1.ObjectIdentifier if !.ReadASN1ObjectIdentifier(&) { return nil, errors.New("x509: invalid certificate policies") } = append(, ) } return , nil } // isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. func ( []byte) bool { := false for , := range { if { if != 0 { return false } continue } switch { case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: = true case 0xff: default: return false } } return true } func ( *Certificate, pkix.Extension) ( bool, error) { // RFC 5280, 4.2.1.10 // NameConstraints ::= SEQUENCE { // permittedSubtrees [0] GeneralSubtrees OPTIONAL, // excludedSubtrees [1] GeneralSubtrees OPTIONAL } // // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree // // GeneralSubtree ::= SEQUENCE { // base GeneralName, // minimum [0] BaseDistance DEFAULT 0, // maximum [1] BaseDistance OPTIONAL } // // BaseDistance ::= INTEGER (0..MAX) := cryptobyte.String(.Value) var , , cryptobyte.String var , bool if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) || !.Empty() || !.ReadOptionalASN1(&, &, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || !.ReadOptionalASN1(&, &, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || !.Empty() { return false, errors.New("x509: invalid NameConstraints extension") } if ! && ! || len() == 0 && len() == 0 { // From RFC 5280, Section 4.2.1.10: // “either the permittedSubtrees field // or the excludedSubtrees MUST be // present” return false, errors.New("x509: empty name constraints extension") } := func( cryptobyte.String) ( []string, []*net.IPNet, , []string, error) { for !.Empty() { var , cryptobyte.String var cryptobyte_asn1.Tag if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) || !.ReadAnyASN1(&, &) { return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") } var ( = cryptobyte_asn1.Tag(2).ContextSpecific() = cryptobyte_asn1.Tag(1).ContextSpecific() = cryptobyte_asn1.Tag(7).ContextSpecific() = cryptobyte_asn1.Tag(6).ContextSpecific() ) switch { case : := string() if := isIA5String(); != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + .Error()) } := if len() > 0 && [0] == '.' { // constraints can have a leading // period to exclude the domain // itself, but that's not valid in a // normal domain name. = [1:] } if , := domainToReverseLabels(); ! { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", ) } = append(, ) case : := len() var , []byte switch { case 8: = [:4] = [4:] case 32: = [:16] = [16:] default: return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", ) } if !isValidIPMask() { return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", ) } = append(, &net.IPNet{IP: net.IP(), Mask: net.IPMask()}) case : := string() if := isIA5String(); != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + .Error()) } // If the constraint contains an @ then // it specifies an exact mailbox name. if strings.Contains(, "@") { if , := parseRFC2821Mailbox(); ! { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", ) } } else { // Otherwise it's a domain name. := if len() > 0 && [0] == '.' { = [1:] } if , := domainToReverseLabels(); ! { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", ) } } = append(, ) case : := string() if := isIA5String(); != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + .Error()) } if net.ParseIP() != nil { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", ) } := if len() > 0 && [0] == '.' { // constraints can have a leading // period to exclude the domain itself, // but that's not valid in a normal // domain name. = [1:] } if , := domainToReverseLabels(); ! { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", ) } = append(, ) default: = true } } return , , , , nil } if .PermittedDNSDomains, .PermittedIPRanges, .PermittedEmailAddresses, .PermittedURIDomains, = (); != nil { return false, } if .ExcludedDNSDomains, .ExcludedIPRanges, .ExcludedEmailAddresses, .ExcludedURIDomains, = (); != nil { return false, } .PermittedDNSDomainsCritical = .Critical return , nil } func ( *Certificate) error { var error for , := range .Extensions { := false if len(.Id) == 4 && .Id[0] == 2 && .Id[1] == 5 && .Id[2] == 29 { switch .Id[3] { case 15: .KeyUsage, = parseKeyUsageExtension(.Value) if != nil { return } case 19: .IsCA, .MaxPathLen, = parseBasicConstraintsExtension(.Value) if != nil { return } .BasicConstraintsValid = true .MaxPathLenZero = .MaxPathLen == 0 case 17: .DNSNames, .EmailAddresses, .IPAddresses, .URIs, = parseSANExtension(.Value) if != nil { return } if len(.DNSNames) == 0 && len(.EmailAddresses) == 0 && len(.IPAddresses) == 0 && len(.URIs) == 0 { // If we didn't parse anything then we do the critical check, below. = true } case 30: , = parseNameConstraintsExtension(, ) if != nil { return } case 31: // RFC 5280, 4.2.1.13 // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint // // DistributionPoint ::= SEQUENCE { // distributionPoint [0] DistributionPointName OPTIONAL, // reasons [1] ReasonFlags OPTIONAL, // cRLIssuer [2] GeneralNames OPTIONAL } // // DistributionPointName ::= CHOICE { // fullName [0] GeneralNames, // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } := cryptobyte.String(.Value) if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid CRL distribution points") } for !.Empty() { var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid CRL distribution point") } var cryptobyte.String var bool if !.ReadOptionalASN1(&, &, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } if ! { continue } if !.ReadASN1(&, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } for !.Empty() { if !.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { break } var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.Tag(6).ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } .CRLDistributionPoints = append(.CRLDistributionPoints, string()) } } case 35: // RFC 5280, 4.2.1.1 := cryptobyte.String(.Value) var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority key identifier") } if .PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { if !.ReadASN1(&, cryptobyte_asn1.Tag(0).ContextSpecific()) { return errors.New("x509: invalid authority key identifier") } .AuthorityKeyId = } case 37: .ExtKeyUsage, .UnknownExtKeyUsage, = parseExtKeyUsageExtension(.Value) if != nil { return } case 14: // RFC 5280, 4.2.1.2 := cryptobyte.String(.Value) var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.OCTET_STRING) { return errors.New("x509: invalid subject key identifier") } .SubjectKeyId = case 32: .PolicyIdentifiers, = parseCertificatePoliciesExtension(.Value) if != nil { return } default: // Unknown extensions are recorded if critical. = true } } else if .Id.Equal(oidExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access := cryptobyte.String(.Value) if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority info access") } for !.Empty() { var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority info access") } var asn1.ObjectIdentifier if !.ReadASN1ObjectIdentifier(&) { return errors.New("x509: invalid authority info access") } if !.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { continue } if !.ReadASN1(&, cryptobyte_asn1.Tag(6).ContextSpecific()) { return errors.New("x509: invalid authority info access") } switch { case .Equal(oidAuthorityInfoAccessOcsp): .OCSPServer = append(.OCSPServer, string()) case .Equal(oidAuthorityInfoAccessIssuers): .IssuingCertificateURL = append(.IssuingCertificateURL, string()) } } } else { // Unknown extensions are recorded if critical. = true } if .Critical && { .UnhandledCriticalExtensions = append(.UnhandledCriticalExtensions, .Id) } } return nil } func ( []byte) (*Certificate, error) { := &Certificate{} := cryptobyte.String() // we read the SEQUENCE including length and tag bytes so that // we can populate Certificate.Raw, before unwrapping the // SEQUENCE so it can be operated on if !.ReadASN1Element(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed certificate") } .Raw = if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed certificate") } var cryptobyte.String // do the same trick again as above to extract the raw // bytes for Certificate.RawTBSCertificate if !.ReadASN1Element(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed tbs certificate") } .RawTBSCertificate = if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed tbs certificate") } if !.ReadOptionalASN1Integer(&.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) { return nil, errors.New("x509: malformed version") } if .Version < 0 { return nil, errors.New("x509: malformed version") } // for backwards compat reasons Version is one-indexed, // rather than zero-indexed as defined in 5280 .Version++ if .Version > 3 { return nil, errors.New("x509: invalid version") } := new(big.Int) if !.ReadASN1Integer() { return nil, errors.New("x509: malformed serial number") } // we ignore the presence of negative serial numbers because // of their prevalence, despite them being invalid // TODO(rolandshoemaker): revist this decision, there are currently // only 10 trusted certificates with negative serial numbers // according to censys.io. .SerialNumber = var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed signature algorithm identifier") } // Before parsing the inner algorithm identifier, extract // the outer algorithm identifier and make sure that they // match. var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed algorithm identifier") } if !bytes.Equal(, ) { return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") } , := parseAI() if != nil { return nil, } .SignatureAlgorithm = getSignatureAlgorithmFromAI() var cryptobyte.String if !.ReadASN1Element(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed issuer") } .RawIssuer = , := parseName() if != nil { return nil, } .Issuer.FillFromRDNSequence() var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed validity") } .NotBefore, .NotAfter, = parseValidity() if != nil { return nil, } var cryptobyte.String if !.ReadASN1Element(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed issuer") } .RawSubject = , := parseName() if != nil { return nil, } .Subject.FillFromRDNSequence() var cryptobyte.String if !.ReadASN1Element(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed spki") } .RawSubjectPublicKeyInfo = if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed spki") } var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed public key algorithm identifier") } , := parseAI() if != nil { return nil, } .PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(.Algorithm) var asn1.BitString if !.ReadASN1BitString(&) { return nil, errors.New("x509: malformed subjectPublicKey") } .PublicKey, = parsePublicKey(.PublicKeyAlgorithm, &publicKeyInfo{ Algorithm: , PublicKey: , }) if != nil { return nil, } if .Version > 1 { if !.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) { return nil, errors.New("x509: malformed issuerUniqueID") } if !.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) { return nil, errors.New("x509: malformed subjectUniqueID") } if .Version == 3 { var cryptobyte.String var bool if !.ReadOptionalASN1(&, &, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) { return nil, errors.New("x509: malformed extensions") } if { if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed extensions") } for !.Empty() { var cryptobyte.String if !.ReadASN1(&, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed extension") } , := parseExtension() if != nil { return nil, } .Extensions = append(.Extensions, ) } = processExtensions() if != nil { return nil, } } } } var asn1.BitString if !.ReadASN1BitString(&) { return nil, errors.New("x509: malformed signature") } .Signature = .RightAlign() return , nil } // ParseCertificate parses a single certificate from the given ASN.1 DER data. func ( []byte) (*Certificate, error) { , := parseCertificate() if != nil { return nil, } if len() != len(.Raw) { return nil, errors.New("x509: trailing data") } return , } // ParseCertificates parses one or more certificates from the given ASN.1 DER // data. The certificates must be concatenated with no intermediate padding. func ( []byte) ([]*Certificate, error) { var []*Certificate for len() > 0 { , := parseCertificate() if != nil { return nil, } = append(, ) = [len(.Raw):] } return , nil }