blob: 6695212a0bb15db3b646c67a151a124b7e193df5 [file] [log] [blame]
// 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/ecdh"
"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(&params, &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(keyData *publicKeyInfo) (any, error) {
oid := keyData.Algorithm.Algorithm
params := keyData.Algorithm.Parameters
der := cryptobyte.String(keyData.PublicKey.RightAlign())
switch {
case oid.Equal(oidPublicKeyRSA):
// RSA public keys must have a NULL in the parameters.
// See RFC 3279, Section 2.3.1.
if !bytes.Equal(params.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 oid.Equal(oidPublicKeyECDSA):
paramsDer := cryptobyte.String(params.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 oid.Equal(oidPublicKeyEd25519):
// RFC 8410, Section 3
// > For all of the OIDs, the parameters MUST be absent.
if len(params.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 oid.Equal(oidPublicKeyX25519):
// RFC 8410, Section 3
// > For all of the OIDs, the parameters MUST be absent.
if len(params.FullBytes) != 0 {
return nil, errors.New("x509: X25519 key encoded with illegal parameters")
}
return ecdh.X25519().NewPublicKey(der)
case oid.Equal(oidPublicKeyDSA):
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(params.FullBytes)
if !paramsDer.ReadASN1(&paramsDer, 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, errors.New("x509: unknown public key algorithm")
}
}
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")
}
if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) {
if !der.ReadASN1Boolean(&isCA) {
return false, 0, errors.New("x509: invalid basic constraints")
}
}
maxPathLen := -1
if der.PeekASN1Tag(cryptobyte_asn1.INTEGER) {
if !der.ReadASN1Integer(&maxPathLen) {
return false, 0, errors.New("x509: invalid basic constraints")
}
}
// 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")
}
if cert.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm {
cert.PublicKey, err = parsePublicKey(&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() {
rce := RevocationListEntry{}
var certSeq cryptobyte.String
if !revokedSeq.ReadASN1Element(&certSeq, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("x509: malformed crl")
}
rce.Raw = certSeq
if !certSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("x509: malformed crl")
}
rce.SerialNumber = new(big.Int)
if !certSeq.ReadASN1Integer(rce.SerialNumber) {
return nil, errors.New("x509: malformed serial number")
}
rce.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
}
if ext.Id.Equal(oidExtensionReasonCode) {
val := cryptobyte.String(ext.Value)
if !val.ReadASN1Enum(&rce.ReasonCode) {
return nil, fmt.Errorf("x509: malformed reasonCode extension")
}
}
rce.Extensions = append(rce.Extensions, ext)
}
}
rl.RevokedCertificateEntries = append(rl.RevokedCertificateEntries, rce)
rcDeprecated := pkix.RevokedCertificate{
SerialNumber: rce.SerialNumber,
RevocationTime: rce.RevocationTime,
Extensions: rce.Extensions,
}
rl.RevokedCertificates = append(rl.RevokedCertificates, rcDeprecated)
}
}
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
}