| // 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 ( |
| "bytes" |
| "crypto/dsa" |
| "crypto/ecdsa" |
| "crypto/ed25519" |
| "crypto/elliptic" |
| "crypto/rsa" |
| "crypto/x509/pkix" |
| "encoding/asn1" |
| "errors" |
| "fmt" |
| "math/big" |
| "net" |
| "net/url" |
| "strconv" |
| "strings" |
| "time" |
| "unicode/utf16" |
| "unicode/utf8" |
| |
| "golang.org/x/crypto/cryptobyte" |
| cryptobyte_asn1 "golang.org/x/crypto/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 isPrintable(b byte) bool { |
| return 'a' <= b && b <= 'z' || |
| 'A' <= b && b <= 'Z' || |
| '0' <= b && b <= '9' || |
| '\'' <= b && b <= ')' || |
| '+' <= b && b <= '/' || |
| b == ' ' || |
| b == ':' || |
| b == '=' || |
| b == '?' || |
| // 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. |
| b == '*' || |
| // 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. |
| b == '&' |
| } |
| |
| // 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 parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) { |
| switch tag { |
| case cryptobyte_asn1.T61String: |
| return string(value), nil |
| case cryptobyte_asn1.PrintableString: |
| for _, b := range value { |
| if !isPrintable(b) { |
| return "", errors.New("invalid PrintableString") |
| } |
| } |
| return string(value), nil |
| case cryptobyte_asn1.UTF8String: |
| if !utf8.Valid(value) { |
| return "", errors.New("invalid UTF-8 string") |
| } |
| return string(value), nil |
| case cryptobyte_asn1.Tag(asn1.TagBMPString): |
| if len(value)%2 != 0 { |
| return "", errors.New("invalid BMPString") |
| } |
| |
| // Strip terminator if present. |
| if l := len(value); l >= 2 && value[l-1] == 0 && value[l-2] == 0 { |
| value = value[:l-2] |
| } |
| |
| s := make([]uint16, 0, len(value)/2) |
| for len(value) > 0 { |
| s = append(s, uint16(value[0])<<8+uint16(value[1])) |
| value = value[2:] |
| } |
| |
| return string(utf16.Decode(s)), nil |
| case cryptobyte_asn1.IA5String: |
| s := string(value) |
| if isIA5String(s) != nil { |
| return "", errors.New("invalid IA5String") |
| } |
| return s, nil |
| case cryptobyte_asn1.Tag(asn1.TagNumericString): |
| for _, b := range value { |
| if !('0' <= b && b <= '9' || b == ' ') { |
| return "", errors.New("invalid NumericString") |
| } |
| } |
| return string(value), nil |
| } |
| return "", fmt.Errorf("unsupported string type: %v", tag) |
| } |
| |
| // 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 parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { |
| if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: invalid RDNSequence") |
| } |
| |
| var rdnSeq pkix.RDNSequence |
| for !raw.Empty() { |
| var rdnSet pkix.RelativeDistinguishedNameSET |
| var set cryptobyte.String |
| if !raw.ReadASN1(&set, cryptobyte_asn1.SET) { |
| return nil, errors.New("x509: invalid RDNSequence") |
| } |
| for !set.Empty() { |
| var atav cryptobyte.String |
| if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: invalid RDNSequence: invalid attribute") |
| } |
| var attr pkix.AttributeTypeAndValue |
| if !atav.ReadASN1ObjectIdentifier(&attr.Type) { |
| return nil, errors.New("x509: invalid RDNSequence: invalid attribute type") |
| } |
| var rawValue cryptobyte.String |
| var valueTag cryptobyte_asn1.Tag |
| if !atav.ReadAnyASN1(&rawValue, &valueTag) { |
| return nil, errors.New("x509: invalid RDNSequence: invalid attribute value") |
| } |
| var err error |
| attr.Value, err = parseASN1String(valueTag, rawValue) |
| if err != nil { |
| return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", err) |
| } |
| rdnSet = append(rdnSet, attr) |
| } |
| |
| rdnSeq = append(rdnSeq, rdnSet) |
| } |
| |
| return &rdnSeq, nil |
| } |
| |
| func parseAI(der cryptobyte.String) (pkix.AlgorithmIdentifier, error) { |
| ai := pkix.AlgorithmIdentifier{} |
| if !der.ReadASN1ObjectIdentifier(&ai.Algorithm) { |
| return ai, errors.New("x509: malformed OID") |
| } |
| if der.Empty() { |
| return ai, nil |
| } |
| var params cryptobyte.String |
| var tag cryptobyte_asn1.Tag |
| if !der.ReadAnyASN1Element(¶ms, &tag) { |
| return ai, errors.New("x509: malformed parameters") |
| } |
| ai.Parameters.Tag = int(tag) |
| ai.Parameters.FullBytes = params |
| return ai, nil |
| } |
| |
| func parseTime(der *cryptobyte.String) (time.Time, error) { |
| var t time.Time |
| switch { |
| case der.PeekASN1Tag(cryptobyte_asn1.UTCTime): |
| if !der.ReadASN1UTCTime(&t) { |
| return t, errors.New("x509: malformed UTCTime") |
| } |
| case der.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime): |
| if !der.ReadASN1GeneralizedTime(&t) { |
| return t, errors.New("x509: malformed GeneralizedTime") |
| } |
| default: |
| return t, errors.New("x509: unsupported time format") |
| } |
| return t, nil |
| } |
| |
| func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) { |
| notBefore, err := parseTime(&der) |
| if err != nil { |
| return time.Time{}, time.Time{}, err |
| } |
| notAfter, err := parseTime(&der) |
| if err != nil { |
| return time.Time{}, time.Time{}, err |
| } |
| |
| return notBefore, notAfter, nil |
| } |
| |
| func parseExtension(der cryptobyte.String) (pkix.Extension, error) { |
| var ext pkix.Extension |
| if !der.ReadASN1ObjectIdentifier(&ext.Id) { |
| return ext, errors.New("x509: malformed extension OID field") |
| } |
| if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { |
| if !der.ReadASN1Boolean(&ext.Critical) { |
| return ext, errors.New("x509: malformed extension critical field") |
| } |
| } |
| var val cryptobyte.String |
| if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) { |
| return ext, errors.New("x509: malformed extension value field") |
| } |
| ext.Value = val |
| return ext, nil |
| } |
| |
| func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (any, error) { |
| der := cryptobyte.String(keyData.PublicKey.RightAlign()) |
| switch algo { |
| case RSA: |
| // RSA public keys must have a NULL in the parameters. |
| // See RFC 3279, Section 2.3.1. |
| if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) { |
| return nil, errors.New("x509: RSA key missing NULL parameters") |
| } |
| |
| p := &pkcs1PublicKey{N: new(big.Int)} |
| if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: invalid RSA public key") |
| } |
| if !der.ReadASN1Integer(p.N) { |
| return nil, errors.New("x509: invalid RSA modulus") |
| } |
| if !der.ReadASN1Integer(&p.E) { |
| return nil, errors.New("x509: invalid RSA public exponent") |
| } |
| |
| if p.N.Sign() <= 0 { |
| return nil, errors.New("x509: RSA modulus is not a positive number") |
| } |
| if p.E <= 0 { |
| return nil, errors.New("x509: RSA public exponent is not a positive number") |
| } |
| |
| pub := &rsa.PublicKey{ |
| E: p.E, |
| N: p.N, |
| } |
| return pub, nil |
| case ECDSA: |
| paramsDer := cryptobyte.String(keyData.Algorithm.Parameters.FullBytes) |
| namedCurveOID := new(asn1.ObjectIdentifier) |
| if !paramsDer.ReadASN1ObjectIdentifier(namedCurveOID) { |
| return nil, errors.New("x509: invalid ECDSA parameters") |
| } |
| namedCurve := namedCurveFromOID(*namedCurveOID) |
| if namedCurve == nil { |
| return nil, errors.New("x509: unsupported elliptic curve") |
| } |
| x, y := elliptic.Unmarshal(namedCurve, der) |
| if x == nil { |
| return nil, errors.New("x509: failed to unmarshal elliptic curve point") |
| } |
| pub := &ecdsa.PublicKey{ |
| Curve: namedCurve, |
| X: x, |
| Y: y, |
| } |
| return pub, nil |
| case Ed25519: |
| // RFC 8410, Section 3 |
| // > For all of the OIDs, the parameters MUST be absent. |
| if len(keyData.Algorithm.Parameters.FullBytes) != 0 { |
| return nil, errors.New("x509: Ed25519 key encoded with illegal parameters") |
| } |
| if len(der) != ed25519.PublicKeySize { |
| return nil, errors.New("x509: wrong Ed25519 public key size") |
| } |
| return ed25519.PublicKey(der), nil |
| case DSA: |
| y := new(big.Int) |
| if !der.ReadASN1Integer(y) { |
| return nil, errors.New("x509: invalid DSA public key") |
| } |
| pub := &dsa.PublicKey{ |
| Y: y, |
| Parameters: dsa.Parameters{ |
| P: new(big.Int), |
| Q: new(big.Int), |
| G: new(big.Int), |
| }, |
| } |
| paramsDer := cryptobyte.String(keyData.Algorithm.Parameters.FullBytes) |
| if !paramsDer.ReadASN1(¶msDer, cryptobyte_asn1.SEQUENCE) || |
| !paramsDer.ReadASN1Integer(pub.Parameters.P) || |
| !paramsDer.ReadASN1Integer(pub.Parameters.Q) || |
| !paramsDer.ReadASN1Integer(pub.Parameters.G) { |
| return nil, errors.New("x509: invalid DSA parameters") |
| } |
| if pub.Y.Sign() <= 0 || pub.Parameters.P.Sign() <= 0 || |
| pub.Parameters.Q.Sign() <= 0 || pub.Parameters.G.Sign() <= 0 { |
| return nil, errors.New("x509: zero or negative DSA parameter") |
| } |
| return pub, nil |
| default: |
| return nil, nil |
| } |
| } |
| |
| func parseKeyUsageExtension(der cryptobyte.String) (KeyUsage, error) { |
| var usageBits asn1.BitString |
| if !der.ReadASN1BitString(&usageBits) { |
| return 0, errors.New("x509: invalid key usage") |
| } |
| |
| var usage int |
| for i := 0; i < 9; i++ { |
| if usageBits.At(i) != 0 { |
| usage |= 1 << uint(i) |
| } |
| } |
| return KeyUsage(usage), nil |
| } |
| |
| func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) { |
| var isCA bool |
| if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { |
| return false, 0, errors.New("x509: invalid basic constraints a") |
| } |
| if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { |
| if !der.ReadASN1Boolean(&isCA) { |
| return false, 0, errors.New("x509: invalid basic constraints b") |
| } |
| } |
| maxPathLen := -1 |
| if !der.Empty() && der.PeekASN1Tag(cryptobyte_asn1.INTEGER) { |
| if !der.ReadASN1Integer(&maxPathLen) { |
| 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 isCA, maxPathLen, nil |
| } |
| |
| func forEachSAN(der cryptobyte.String, callback func(tag int, data []byte) error) error { |
| if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { |
| return errors.New("x509: invalid subject alternative names") |
| } |
| for !der.Empty() { |
| var san cryptobyte.String |
| var tag cryptobyte_asn1.Tag |
| if !der.ReadAnyASN1(&san, &tag) { |
| return errors.New("x509: invalid subject alternative name") |
| } |
| if err := callback(int(tag^0x80), san); err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { |
| err = forEachSAN(der, func(tag int, data []byte) error { |
| switch tag { |
| case nameTypeEmail: |
| email := string(data) |
| if err := isIA5String(email); err != nil { |
| return errors.New("x509: SAN rfc822Name is malformed") |
| } |
| emailAddresses = append(emailAddresses, email) |
| case nameTypeDNS: |
| name := string(data) |
| if err := isIA5String(name); err != nil { |
| return errors.New("x509: SAN dNSName is malformed") |
| } |
| dnsNames = append(dnsNames, string(name)) |
| case nameTypeURI: |
| uriStr := string(data) |
| if err := isIA5String(uriStr); err != nil { |
| return errors.New("x509: SAN uniformResourceIdentifier is malformed") |
| } |
| uri, err := url.Parse(uriStr) |
| if err != nil { |
| return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err) |
| } |
| if len(uri.Host) > 0 { |
| if _, ok := domainToReverseLabels(uri.Host); !ok { |
| return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr) |
| } |
| } |
| uris = append(uris, uri) |
| case nameTypeIP: |
| switch len(data) { |
| case net.IPv4len, net.IPv6len: |
| ipAddresses = append(ipAddresses, data) |
| default: |
| return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data))) |
| } |
| } |
| |
| return nil |
| }) |
| |
| return |
| } |
| |
| func parseExtKeyUsageExtension(der cryptobyte.String) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) { |
| var extKeyUsages []ExtKeyUsage |
| var unknownUsages []asn1.ObjectIdentifier |
| if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { |
| return nil, nil, errors.New("x509: invalid extended key usages") |
| } |
| for !der.Empty() { |
| var eku asn1.ObjectIdentifier |
| if !der.ReadASN1ObjectIdentifier(&eku) { |
| return nil, nil, errors.New("x509: invalid extended key usages") |
| } |
| if extKeyUsage, ok := extKeyUsageFromOID(eku); ok { |
| extKeyUsages = append(extKeyUsages, extKeyUsage) |
| } else { |
| unknownUsages = append(unknownUsages, eku) |
| } |
| } |
| return extKeyUsages, unknownUsages, nil |
| } |
| |
| func parseCertificatePoliciesExtension(der cryptobyte.String) ([]asn1.ObjectIdentifier, error) { |
| var oids []asn1.ObjectIdentifier |
| if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: invalid certificate policies") |
| } |
| for !der.Empty() { |
| var cp cryptobyte.String |
| if !der.ReadASN1(&cp, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: invalid certificate policies") |
| } |
| var oid asn1.ObjectIdentifier |
| if !cp.ReadASN1ObjectIdentifier(&oid) { |
| return nil, errors.New("x509: invalid certificate policies") |
| } |
| oids = append(oids, oid) |
| } |
| |
| return oids, nil |
| } |
| |
| // isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. |
| func isValidIPMask(mask []byte) bool { |
| seenZero := false |
| |
| for _, b := range mask { |
| if seenZero { |
| if b != 0 { |
| return false |
| } |
| |
| continue |
| } |
| |
| switch b { |
| case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: |
| seenZero = true |
| case 0xff: |
| default: |
| return false |
| } |
| } |
| |
| return true |
| } |
| |
| func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err 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) |
| |
| outer := cryptobyte.String(e.Value) |
| var toplevel, permitted, excluded cryptobyte.String |
| var havePermitted, haveExcluded bool |
| if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || |
| !outer.Empty() || |
| !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || |
| !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || |
| !toplevel.Empty() { |
| return false, errors.New("x509: invalid NameConstraints extension") |
| } |
| |
| if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 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") |
| } |
| |
| getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { |
| for !subtrees.Empty() { |
| var seq, value cryptobyte.String |
| var tag cryptobyte_asn1.Tag |
| if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || |
| !seq.ReadAnyASN1(&value, &tag) { |
| return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") |
| } |
| |
| var ( |
| dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() |
| emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() |
| ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() |
| uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() |
| ) |
| |
| switch tag { |
| case dnsTag: |
| domain := string(value) |
| if err := isIA5String(domain); err != nil { |
| return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) |
| } |
| |
| trimmedDomain := domain |
| if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { |
| // constraints can have a leading |
| // period to exclude the domain |
| // itself, but that's not valid in a |
| // normal domain name. |
| trimmedDomain = trimmedDomain[1:] |
| } |
| if _, ok := domainToReverseLabels(trimmedDomain); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) |
| } |
| dnsNames = append(dnsNames, domain) |
| |
| case ipTag: |
| l := len(value) |
| var ip, mask []byte |
| |
| switch l { |
| case 8: |
| ip = value[:4] |
| mask = value[4:] |
| |
| case 32: |
| ip = value[:16] |
| mask = value[16:] |
| |
| default: |
| return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) |
| } |
| |
| if !isValidIPMask(mask) { |
| return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) |
| } |
| |
| ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) |
| |
| case emailTag: |
| constraint := string(value) |
| if err := isIA5String(constraint); err != nil { |
| return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) |
| } |
| |
| // If the constraint contains an @ then |
| // it specifies an exact mailbox name. |
| if strings.Contains(constraint, "@") { |
| if _, ok := parseRFC2821Mailbox(constraint); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) |
| } |
| } else { |
| // Otherwise it's a domain name. |
| domain := constraint |
| if len(domain) > 0 && domain[0] == '.' { |
| domain = domain[1:] |
| } |
| if _, ok := domainToReverseLabels(domain); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) |
| } |
| } |
| emails = append(emails, constraint) |
| |
| case uriTag: |
| domain := string(value) |
| if err := isIA5String(domain); err != nil { |
| return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) |
| } |
| |
| if net.ParseIP(domain) != nil { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) |
| } |
| |
| trimmedDomain := domain |
| if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { |
| // constraints can have a leading |
| // period to exclude the domain itself, |
| // but that's not valid in a normal |
| // domain name. |
| trimmedDomain = trimmedDomain[1:] |
| } |
| if _, ok := domainToReverseLabels(trimmedDomain); !ok { |
| return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) |
| } |
| uriDomains = append(uriDomains, domain) |
| |
| default: |
| unhandled = true |
| } |
| } |
| |
| return dnsNames, ips, emails, uriDomains, nil |
| } |
| |
| if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { |
| return false, err |
| } |
| if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { |
| return false, err |
| } |
| out.PermittedDNSDomainsCritical = e.Critical |
| |
| return unhandled, nil |
| } |
| |
| func processExtensions(out *Certificate) error { |
| var err error |
| for _, e := range out.Extensions { |
| unhandled := false |
| |
| if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { |
| switch e.Id[3] { |
| case 15: |
| out.KeyUsage, err = parseKeyUsageExtension(e.Value) |
| if err != nil { |
| return err |
| } |
| case 19: |
| out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value) |
| if err != nil { |
| return err |
| } |
| out.BasicConstraintsValid = true |
| out.MaxPathLenZero = out.MaxPathLen == 0 |
| case 17: |
| out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value) |
| if err != nil { |
| return err |
| } |
| |
| if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { |
| // If we didn't parse anything then we do the critical check, below. |
| unhandled = true |
| } |
| |
| case 30: |
| unhandled, err = parseNameConstraintsExtension(out, e) |
| if err != nil { |
| return err |
| } |
| |
| 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 } |
| val := cryptobyte.String(e.Value) |
| if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { |
| return errors.New("x509: invalid CRL distribution points") |
| } |
| for !val.Empty() { |
| var dpDER cryptobyte.String |
| if !val.ReadASN1(&dpDER, cryptobyte_asn1.SEQUENCE) { |
| return errors.New("x509: invalid CRL distribution point") |
| } |
| var dpNameDER cryptobyte.String |
| var dpNamePresent bool |
| if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { |
| return errors.New("x509: invalid CRL distribution point") |
| } |
| if !dpNamePresent { |
| continue |
| } |
| if !dpNameDER.ReadASN1(&dpNameDER, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { |
| return errors.New("x509: invalid CRL distribution point") |
| } |
| for !dpNameDER.Empty() { |
| if !dpNameDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { |
| break |
| } |
| var uri cryptobyte.String |
| if !dpNameDER.ReadASN1(&uri, cryptobyte_asn1.Tag(6).ContextSpecific()) { |
| return errors.New("x509: invalid CRL distribution point") |
| } |
| out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(uri)) |
| } |
| } |
| |
| case 35: |
| // RFC 5280, 4.2.1.1 |
| val := cryptobyte.String(e.Value) |
| var akid cryptobyte.String |
| if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { |
| return errors.New("x509: invalid authority key identifier") |
| } |
| if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { |
| if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { |
| return errors.New("x509: invalid authority key identifier") |
| } |
| out.AuthorityKeyId = akid |
| } |
| case 37: |
| out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value) |
| if err != nil { |
| return err |
| } |
| case 14: |
| // RFC 5280, 4.2.1.2 |
| val := cryptobyte.String(e.Value) |
| var skid cryptobyte.String |
| if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) { |
| return errors.New("x509: invalid subject key identifier") |
| } |
| out.SubjectKeyId = skid |
| case 32: |
| out.PolicyIdentifiers, err = parseCertificatePoliciesExtension(e.Value) |
| if err != nil { |
| return err |
| } |
| default: |
| // Unknown extensions are recorded if critical. |
| unhandled = true |
| } |
| } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { |
| // RFC 5280 4.2.2.1: Authority Information Access |
| val := cryptobyte.String(e.Value) |
| if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { |
| return errors.New("x509: invalid authority info access") |
| } |
| for !val.Empty() { |
| var aiaDER cryptobyte.String |
| if !val.ReadASN1(&aiaDER, cryptobyte_asn1.SEQUENCE) { |
| return errors.New("x509: invalid authority info access") |
| } |
| var method asn1.ObjectIdentifier |
| if !aiaDER.ReadASN1ObjectIdentifier(&method) { |
| return errors.New("x509: invalid authority info access") |
| } |
| if !aiaDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { |
| continue |
| } |
| if !aiaDER.ReadASN1(&aiaDER, cryptobyte_asn1.Tag(6).ContextSpecific()) { |
| return errors.New("x509: invalid authority info access") |
| } |
| switch { |
| case method.Equal(oidAuthorityInfoAccessOcsp): |
| out.OCSPServer = append(out.OCSPServer, string(aiaDER)) |
| case method.Equal(oidAuthorityInfoAccessIssuers): |
| out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(aiaDER)) |
| } |
| } |
| } else { |
| // Unknown extensions are recorded if critical. |
| unhandled = true |
| } |
| |
| if e.Critical && unhandled { |
| out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) |
| } |
| } |
| |
| return nil |
| } |
| |
| func parseCertificate(der []byte) (*Certificate, error) { |
| cert := &Certificate{} |
| |
| input := cryptobyte.String(der) |
| // 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 !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed certificate") |
| } |
| cert.Raw = input |
| if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed certificate") |
| } |
| |
| var tbs cryptobyte.String |
| // do the same trick again as above to extract the raw |
| // bytes for Certificate.RawTBSCertificate |
| if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed tbs certificate") |
| } |
| cert.RawTBSCertificate = tbs |
| if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed tbs certificate") |
| } |
| |
| if !tbs.ReadOptionalASN1Integer(&cert.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) { |
| return nil, errors.New("x509: malformed version") |
| } |
| if cert.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 |
| cert.Version++ |
| if cert.Version > 3 { |
| return nil, errors.New("x509: invalid version") |
| } |
| |
| serial := new(big.Int) |
| if !tbs.ReadASN1Integer(serial) { |
| 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): revisit this decision, there are currently |
| // only 10 trusted certificates with negative serial numbers |
| // according to censys.io. |
| cert.SerialNumber = serial |
| |
| var sigAISeq cryptobyte.String |
| if !tbs.ReadASN1(&sigAISeq, 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 outerSigAISeq cryptobyte.String |
| if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed algorithm identifier") |
| } |
| if !bytes.Equal(outerSigAISeq, sigAISeq) { |
| return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") |
| } |
| sigAI, err := parseAI(sigAISeq) |
| if err != nil { |
| return nil, err |
| } |
| cert.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) |
| |
| var issuerSeq cryptobyte.String |
| if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed issuer") |
| } |
| cert.RawIssuer = issuerSeq |
| issuerRDNs, err := parseName(issuerSeq) |
| if err != nil { |
| return nil, err |
| } |
| cert.Issuer.FillFromRDNSequence(issuerRDNs) |
| |
| var validity cryptobyte.String |
| if !tbs.ReadASN1(&validity, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed validity") |
| } |
| cert.NotBefore, cert.NotAfter, err = parseValidity(validity) |
| if err != nil { |
| return nil, err |
| } |
| |
| var subjectSeq cryptobyte.String |
| if !tbs.ReadASN1Element(&subjectSeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed issuer") |
| } |
| cert.RawSubject = subjectSeq |
| subjectRDNs, err := parseName(subjectSeq) |
| if err != nil { |
| return nil, err |
| } |
| cert.Subject.FillFromRDNSequence(subjectRDNs) |
| |
| var spki cryptobyte.String |
| if !tbs.ReadASN1Element(&spki, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed spki") |
| } |
| cert.RawSubjectPublicKeyInfo = spki |
| if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed spki") |
| } |
| var pkAISeq cryptobyte.String |
| if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed public key algorithm identifier") |
| } |
| pkAI, err := parseAI(pkAISeq) |
| if err != nil { |
| return nil, err |
| } |
| cert.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(pkAI.Algorithm) |
| var spk asn1.BitString |
| if !spki.ReadASN1BitString(&spk) { |
| return nil, errors.New("x509: malformed subjectPublicKey") |
| } |
| cert.PublicKey, err = parsePublicKey(cert.PublicKeyAlgorithm, &publicKeyInfo{ |
| Algorithm: pkAI, |
| PublicKey: spk, |
| }) |
| if err != nil { |
| return nil, err |
| } |
| |
| if cert.Version > 1 { |
| if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) { |
| return nil, errors.New("x509: malformed issuerUniqueID") |
| } |
| if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) { |
| return nil, errors.New("x509: malformed subjectUniqueID") |
| } |
| if cert.Version == 3 { |
| var extensions cryptobyte.String |
| var present bool |
| if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) { |
| return nil, errors.New("x509: malformed extensions") |
| } |
| if present { |
| seenExts := make(map[string]bool) |
| if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed extensions") |
| } |
| for !extensions.Empty() { |
| var extension cryptobyte.String |
| if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed extension") |
| } |
| ext, err := parseExtension(extension) |
| if err != nil { |
| return nil, err |
| } |
| oidStr := ext.Id.String() |
| if seenExts[oidStr] { |
| return nil, errors.New("x509: certificate contains duplicate extensions") |
| } |
| seenExts[oidStr] = true |
| cert.Extensions = append(cert.Extensions, ext) |
| } |
| err = processExtensions(cert) |
| if err != nil { |
| return nil, err |
| } |
| } |
| } |
| } |
| |
| var signature asn1.BitString |
| if !input.ReadASN1BitString(&signature) { |
| return nil, errors.New("x509: malformed signature") |
| } |
| cert.Signature = signature.RightAlign() |
| |
| return cert, nil |
| } |
| |
| // ParseCertificate parses a single certificate from the given ASN.1 DER data. |
| func ParseCertificate(der []byte) (*Certificate, error) { |
| cert, err := parseCertificate(der) |
| if err != nil { |
| return nil, err |
| } |
| if len(der) != len(cert.Raw) { |
| return nil, errors.New("x509: trailing data") |
| } |
| return cert, err |
| } |
| |
| // ParseCertificates parses one or more certificates from the given ASN.1 DER |
| // data. The certificates must be concatenated with no intermediate padding. |
| func ParseCertificates(der []byte) ([]*Certificate, error) { |
| var certs []*Certificate |
| for len(der) > 0 { |
| cert, err := parseCertificate(der) |
| if err != nil { |
| return nil, err |
| } |
| certs = append(certs, cert) |
| der = der[len(cert.Raw):] |
| } |
| return certs, nil |
| } |
| |
| // The X.509 standards confusingly 1-indexed the version names, but 0-indexed |
| // the actual encoded version, so the version for X.509v2 is 1. |
| const x509v2Version = 1 |
| |
| // ParseRevocationList parses a X509 v2 Certificate Revocation List from the given |
| // ASN.1 DER data. |
| func ParseRevocationList(der []byte) (*RevocationList, error) { |
| rl := &RevocationList{} |
| |
| input := cryptobyte.String(der) |
| // we read the SEQUENCE including length and tag bytes so that |
| // we can populate RevocationList.Raw, before unwrapping the |
| // SEQUENCE so it can be operated on |
| if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed crl") |
| } |
| rl.Raw = input |
| if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed crl") |
| } |
| |
| var tbs cryptobyte.String |
| // do the same trick again as above to extract the raw |
| // bytes for Certificate.RawTBSCertificate |
| if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed tbs crl") |
| } |
| rl.RawTBSRevocationList = tbs |
| if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed tbs crl") |
| } |
| |
| var version int |
| if !tbs.PeekASN1Tag(cryptobyte_asn1.INTEGER) { |
| return nil, errors.New("x509: unsupported crl version") |
| } |
| if !tbs.ReadASN1Integer(&version) { |
| return nil, errors.New("x509: malformed crl") |
| } |
| if version != x509v2Version { |
| return nil, fmt.Errorf("x509: unsupported crl version: %d", version) |
| } |
| |
| var sigAISeq cryptobyte.String |
| if !tbs.ReadASN1(&sigAISeq, 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 outerSigAISeq cryptobyte.String |
| if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed algorithm identifier") |
| } |
| if !bytes.Equal(outerSigAISeq, sigAISeq) { |
| return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") |
| } |
| sigAI, err := parseAI(sigAISeq) |
| if err != nil { |
| return nil, err |
| } |
| rl.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) |
| |
| var signature asn1.BitString |
| if !input.ReadASN1BitString(&signature) { |
| return nil, errors.New("x509: malformed signature") |
| } |
| rl.Signature = signature.RightAlign() |
| |
| var issuerSeq cryptobyte.String |
| if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed issuer") |
| } |
| rl.RawIssuer = issuerSeq |
| issuerRDNs, err := parseName(issuerSeq) |
| if err != nil { |
| return nil, err |
| } |
| rl.Issuer.FillFromRDNSequence(issuerRDNs) |
| |
| rl.ThisUpdate, err = parseTime(&tbs) |
| if err != nil { |
| return nil, err |
| } |
| if tbs.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime) || tbs.PeekASN1Tag(cryptobyte_asn1.UTCTime) { |
| rl.NextUpdate, err = parseTime(&tbs) |
| if err != nil { |
| return nil, err |
| } |
| } |
| |
| if tbs.PeekASN1Tag(cryptobyte_asn1.SEQUENCE) { |
| var revokedSeq cryptobyte.String |
| if !tbs.ReadASN1(&revokedSeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed crl") |
| } |
| for !revokedSeq.Empty() { |
| var certSeq cryptobyte.String |
| if !revokedSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed crl") |
| } |
| rc := pkix.RevokedCertificate{} |
| rc.SerialNumber = new(big.Int) |
| if !certSeq.ReadASN1Integer(rc.SerialNumber) { |
| return nil, errors.New("x509: malformed serial number") |
| } |
| rc.RevocationTime, err = parseTime(&certSeq) |
| if err != nil { |
| return nil, err |
| } |
| var extensions cryptobyte.String |
| var present bool |
| if !certSeq.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed extensions") |
| } |
| if present { |
| for !extensions.Empty() { |
| var extension cryptobyte.String |
| if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed extension") |
| } |
| ext, err := parseExtension(extension) |
| if err != nil { |
| return nil, err |
| } |
| rc.Extensions = append(rc.Extensions, ext) |
| } |
| } |
| |
| rl.RevokedCertificates = append(rl.RevokedCertificates, rc) |
| } |
| } |
| |
| var extensions cryptobyte.String |
| var present bool |
| if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { |
| return nil, errors.New("x509: malformed extensions") |
| } |
| if present { |
| if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed extensions") |
| } |
| for !extensions.Empty() { |
| var extension cryptobyte.String |
| if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { |
| return nil, errors.New("x509: malformed extension") |
| } |
| ext, err := parseExtension(extension) |
| if err != nil { |
| return nil, err |
| } |
| if ext.Id.Equal(oidExtensionAuthorityKeyId) { |
| rl.AuthorityKeyId = ext.Value |
| } else if ext.Id.Equal(oidExtensionCRLNumber) { |
| value := cryptobyte.String(ext.Value) |
| rl.Number = new(big.Int) |
| if !value.ReadASN1Integer(rl.Number) { |
| return nil, errors.New("x509: malformed crl number") |
| } |
| } |
| rl.Extensions = append(rl.Extensions, ext) |
| } |
| } |
| |
| return rl, nil |
| } |