k8s.io/kubernetes@v1.29.3/pkg/apis/certificates/validation/validation.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package validation
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/x509"
    22  	"encoding/pem"
    23  	"fmt"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	v1 "k8s.io/api/core/v1"
    27  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    28  	"k8s.io/apimachinery/pkg/util/sets"
    29  	"k8s.io/apimachinery/pkg/util/validation/field"
    30  	utilcert "k8s.io/client-go/util/cert"
    31  	"k8s.io/kubernetes/pkg/apis/certificates"
    32  	apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
    33  )
    34  
    35  var (
    36  	// trueConditionTypes is the set of condition types which may only have a status of True if present
    37  	trueConditionTypes = sets.NewString(
    38  		string(certificates.CertificateApproved),
    39  		string(certificates.CertificateDenied),
    40  		string(certificates.CertificateFailed),
    41  	)
    42  
    43  	trueStatusOnly  = sets.NewString(string(v1.ConditionTrue))
    44  	allStatusValues = sets.NewString(string(v1.ConditionTrue), string(v1.ConditionFalse), string(v1.ConditionUnknown))
    45  )
    46  
    47  type certificateValidationOptions struct {
    48  	// The following allow modifications only permitted via certain update paths
    49  
    50  	// allow populating/modifying Approved/Denied conditions
    51  	allowSettingApprovalConditions bool
    52  	// allow populating status.certificate
    53  	allowSettingCertificate bool
    54  
    55  	// allow Approved and Denied conditions to be exist.
    56  	// we tolerate this when the problem is already present in the persisted object for compatibility.
    57  	allowBothApprovedAndDenied bool
    58  
    59  	// The following are bad things we tolerate for compatibility reasons:
    60  	// * in requests made via the v1beta1 API
    61  	// * in update requests where the problem is already present in the persisted object
    62  
    63  	// allow modifying status.certificate on an update where the old object has a different certificate
    64  	allowResettingCertificate bool
    65  	// allow the legacy-unknown signerName
    66  	allowLegacySignerName bool
    67  	// allow conditions with duplicate types
    68  	allowDuplicateConditionTypes bool
    69  	// allow conditions with "" types
    70  	allowEmptyConditionType bool
    71  	// allow arbitrary content in status.certificate
    72  	allowArbitraryCertificate bool
    73  	// allow usages values outside the known set
    74  	allowUnknownUsages bool
    75  	// allow duplicate usages values
    76  	allowDuplicateUsages bool
    77  }
    78  
    79  // validateCSR validates the signature and formatting of a base64-wrapped,
    80  // PEM-encoded PKCS#10 certificate signing request. If this is invalid, we must
    81  // not accept the CSR for further processing.
    82  func validateCSR(obj *certificates.CertificateSigningRequest) error {
    83  	csr, err := certificates.ParseCSR(obj.Spec.Request)
    84  	if err != nil {
    85  		return err
    86  	}
    87  	// check that the signature is valid
    88  	return csr.CheckSignature()
    89  }
    90  
    91  func validateCertificate(pemData []byte) error {
    92  	if len(pemData) == 0 {
    93  		return nil
    94  	}
    95  
    96  	blocks := 0
    97  	for {
    98  		block, remainingData := pem.Decode(pemData)
    99  		if block == nil {
   100  			break
   101  		}
   102  
   103  		if block.Type != utilcert.CertificateBlockType {
   104  			return fmt.Errorf("only CERTIFICATE PEM blocks are allowed, found %q", block.Type)
   105  		}
   106  		if len(block.Headers) != 0 {
   107  			return fmt.Errorf("no PEM block headers are permitted")
   108  		}
   109  		blocks++
   110  
   111  		certs, err := x509.ParseCertificates(block.Bytes)
   112  		if err != nil {
   113  			return err
   114  		}
   115  		if len(certs) == 0 {
   116  			return fmt.Errorf("found CERTIFICATE PEM block containing 0 certificates")
   117  		}
   118  
   119  		pemData = remainingData
   120  	}
   121  
   122  	if blocks == 0 {
   123  		return fmt.Errorf("must contain at least one CERTIFICATE PEM block")
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  // We don't care what you call your certificate requests.
   130  func ValidateCertificateRequestName(name string, prefix bool) []string {
   131  	return nil
   132  }
   133  
   134  func ValidateCertificateSigningRequestCreate(csr *certificates.CertificateSigningRequest) field.ErrorList {
   135  	opts := getValidationOptions(csr, nil)
   136  	return validateCertificateSigningRequest(csr, opts)
   137  }
   138  
   139  var (
   140  	allValidUsages = sets.NewString(
   141  		string(certificates.UsageSigning),
   142  		string(certificates.UsageDigitalSignature),
   143  		string(certificates.UsageContentCommitment),
   144  		string(certificates.UsageKeyEncipherment),
   145  		string(certificates.UsageKeyAgreement),
   146  		string(certificates.UsageDataEncipherment),
   147  		string(certificates.UsageCertSign),
   148  		string(certificates.UsageCRLSign),
   149  		string(certificates.UsageEncipherOnly),
   150  		string(certificates.UsageDecipherOnly),
   151  		string(certificates.UsageAny),
   152  		string(certificates.UsageServerAuth),
   153  		string(certificates.UsageClientAuth),
   154  		string(certificates.UsageCodeSigning),
   155  		string(certificates.UsageEmailProtection),
   156  		string(certificates.UsageSMIME),
   157  		string(certificates.UsageIPsecEndSystem),
   158  		string(certificates.UsageIPsecTunnel),
   159  		string(certificates.UsageIPsecUser),
   160  		string(certificates.UsageTimestamping),
   161  		string(certificates.UsageOCSPSigning),
   162  		string(certificates.UsageMicrosoftSGC),
   163  		string(certificates.UsageNetscapeSGC),
   164  	)
   165  )
   166  
   167  func validateCertificateSigningRequest(csr *certificates.CertificateSigningRequest, opts certificateValidationOptions) field.ErrorList {
   168  	isNamespaced := false
   169  	allErrs := apivalidation.ValidateObjectMeta(&csr.ObjectMeta, isNamespaced, ValidateCertificateRequestName, field.NewPath("metadata"))
   170  
   171  	specPath := field.NewPath("spec")
   172  	err := validateCSR(csr)
   173  	if err != nil {
   174  		allErrs = append(allErrs, field.Invalid(specPath.Child("request"), csr.Spec.Request, fmt.Sprintf("%v", err)))
   175  	}
   176  	if len(csr.Spec.Usages) == 0 {
   177  		allErrs = append(allErrs, field.Required(specPath.Child("usages"), ""))
   178  	}
   179  	if !opts.allowUnknownUsages {
   180  		for i, usage := range csr.Spec.Usages {
   181  			if !allValidUsages.Has(string(usage)) {
   182  				allErrs = append(allErrs, field.NotSupported(specPath.Child("usages").Index(i), usage, allValidUsages.List()))
   183  			}
   184  		}
   185  	}
   186  	if !opts.allowDuplicateUsages {
   187  		seen := make(map[certificates.KeyUsage]bool, len(csr.Spec.Usages))
   188  		for i, usage := range csr.Spec.Usages {
   189  			if seen[usage] {
   190  				allErrs = append(allErrs, field.Duplicate(specPath.Child("usages").Index(i), usage))
   191  			}
   192  			seen[usage] = true
   193  		}
   194  	}
   195  	if !opts.allowLegacySignerName && csr.Spec.SignerName == certificates.LegacyUnknownSignerName {
   196  		allErrs = append(allErrs, field.Invalid(specPath.Child("signerName"), csr.Spec.SignerName, "the legacy signerName is not allowed via this API version"))
   197  	} else {
   198  		allErrs = append(allErrs, apivalidation.ValidateSignerName(specPath.Child("signerName"), csr.Spec.SignerName)...)
   199  	}
   200  	if csr.Spec.ExpirationSeconds != nil && *csr.Spec.ExpirationSeconds < 600 {
   201  		allErrs = append(allErrs, field.Invalid(specPath.Child("expirationSeconds"), *csr.Spec.ExpirationSeconds, "may not specify a duration less than 600 seconds (10 minutes)"))
   202  	}
   203  	allErrs = append(allErrs, validateConditions(field.NewPath("status", "conditions"), csr, opts)...)
   204  
   205  	if !opts.allowArbitraryCertificate {
   206  		if err := validateCertificate(csr.Status.Certificate); err != nil {
   207  			allErrs = append(allErrs, field.Invalid(field.NewPath("status", "certificate"), "<certificate data>", err.Error()))
   208  		}
   209  	}
   210  
   211  	return allErrs
   212  }
   213  
   214  func validateConditions(fldPath *field.Path, csr *certificates.CertificateSigningRequest, opts certificateValidationOptions) field.ErrorList {
   215  	allErrs := field.ErrorList{}
   216  
   217  	seenTypes := map[certificates.RequestConditionType]bool{}
   218  	hasApproved := false
   219  	hasDenied := false
   220  
   221  	for i, c := range csr.Status.Conditions {
   222  
   223  		if !opts.allowEmptyConditionType {
   224  			if len(c.Type) == 0 {
   225  				allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("type"), ""))
   226  			}
   227  		}
   228  
   229  		allowedStatusValues := allStatusValues
   230  		if trueConditionTypes.Has(string(c.Type)) {
   231  			allowedStatusValues = trueStatusOnly
   232  		}
   233  		switch {
   234  		case c.Status == "":
   235  			allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("status"), ""))
   236  		case !allowedStatusValues.Has(string(c.Status)):
   237  			allErrs = append(allErrs, field.NotSupported(fldPath.Index(i).Child("status"), c.Status, allowedStatusValues.List()))
   238  		}
   239  
   240  		if !opts.allowBothApprovedAndDenied {
   241  			switch c.Type {
   242  			case certificates.CertificateApproved:
   243  				hasApproved = true
   244  				if hasDenied {
   245  					allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("type"), c.Type, "Approved and Denied conditions are mutually exclusive"))
   246  				}
   247  			case certificates.CertificateDenied:
   248  				hasDenied = true
   249  				if hasApproved {
   250  					allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("type"), c.Type, "Approved and Denied conditions are mutually exclusive"))
   251  				}
   252  			}
   253  		}
   254  
   255  		if !opts.allowDuplicateConditionTypes {
   256  			if seenTypes[c.Type] {
   257  				allErrs = append(allErrs, field.Duplicate(fldPath.Index(i).Child("type"), c.Type))
   258  			}
   259  			seenTypes[c.Type] = true
   260  		}
   261  	}
   262  
   263  	return allErrs
   264  }
   265  
   266  func ValidateCertificateSigningRequestUpdate(newCSR, oldCSR *certificates.CertificateSigningRequest) field.ErrorList {
   267  	opts := getValidationOptions(newCSR, oldCSR)
   268  	return validateCertificateSigningRequestUpdate(newCSR, oldCSR, opts)
   269  }
   270  
   271  func ValidateCertificateSigningRequestStatusUpdate(newCSR, oldCSR *certificates.CertificateSigningRequest) field.ErrorList {
   272  	opts := getValidationOptions(newCSR, oldCSR)
   273  	opts.allowSettingCertificate = true
   274  	return validateCertificateSigningRequestUpdate(newCSR, oldCSR, opts)
   275  }
   276  
   277  func ValidateCertificateSigningRequestApprovalUpdate(newCSR, oldCSR *certificates.CertificateSigningRequest) field.ErrorList {
   278  	opts := getValidationOptions(newCSR, oldCSR)
   279  	opts.allowSettingApprovalConditions = true
   280  	return validateCertificateSigningRequestUpdate(newCSR, oldCSR, opts)
   281  }
   282  
   283  func validateCertificateSigningRequestUpdate(newCSR, oldCSR *certificates.CertificateSigningRequest, opts certificateValidationOptions) field.ErrorList {
   284  	validationErrorList := validateCertificateSigningRequest(newCSR, opts)
   285  	metaUpdateErrorList := apivalidation.ValidateObjectMetaUpdate(&newCSR.ObjectMeta, &oldCSR.ObjectMeta, field.NewPath("metadata"))
   286  
   287  	// prevent removal of existing Approved/Denied/Failed conditions
   288  	for _, t := range []certificates.RequestConditionType{certificates.CertificateApproved, certificates.CertificateDenied, certificates.CertificateFailed} {
   289  		oldConditions := findConditions(oldCSR, t)
   290  		newConditions := findConditions(newCSR, t)
   291  		if len(newConditions) < len(oldConditions) {
   292  			validationErrorList = append(validationErrorList, field.Forbidden(field.NewPath("status", "conditions"), fmt.Sprintf("updates may not remove a condition of type %q", t)))
   293  		}
   294  	}
   295  
   296  	if !opts.allowSettingApprovalConditions {
   297  		// prevent addition/removal/modification of Approved/Denied conditions
   298  		for _, t := range []certificates.RequestConditionType{certificates.CertificateApproved, certificates.CertificateDenied} {
   299  			oldConditions := findConditions(oldCSR, t)
   300  			newConditions := findConditions(newCSR, t)
   301  			switch {
   302  			case len(newConditions) < len(oldConditions):
   303  				// removals are prevented above
   304  			case len(newConditions) > len(oldConditions):
   305  				validationErrorList = append(validationErrorList, field.Forbidden(field.NewPath("status", "conditions"), fmt.Sprintf("updates may not add a condition of type %q", t)))
   306  			case !apiequality.Semantic.DeepEqual(oldConditions, newConditions):
   307  				conditionDiff := cmp.Diff(oldConditions, newConditions)
   308  				validationErrorList = append(validationErrorList, field.Forbidden(field.NewPath("status", "conditions"), fmt.Sprintf("updates may not modify a condition of type %q\n%v", t, conditionDiff)))
   309  			}
   310  		}
   311  	}
   312  
   313  	if !bytes.Equal(newCSR.Status.Certificate, oldCSR.Status.Certificate) {
   314  		if !opts.allowSettingCertificate {
   315  			validationErrorList = append(validationErrorList, field.Forbidden(field.NewPath("status", "certificate"), "updates may not set certificate content"))
   316  		} else if !opts.allowResettingCertificate && len(oldCSR.Status.Certificate) > 0 {
   317  			validationErrorList = append(validationErrorList, field.Forbidden(field.NewPath("status", "certificate"), "updates may not modify existing certificate content"))
   318  		}
   319  	}
   320  
   321  	return append(validationErrorList, metaUpdateErrorList...)
   322  }
   323  
   324  // findConditions returns all instances of conditions of the specified type
   325  func findConditions(csr *certificates.CertificateSigningRequest, conditionType certificates.RequestConditionType) []certificates.CertificateSigningRequestCondition {
   326  	var retval []certificates.CertificateSigningRequestCondition
   327  	for i, c := range csr.Status.Conditions {
   328  		if c.Type == conditionType {
   329  			retval = append(retval, csr.Status.Conditions[i])
   330  		}
   331  	}
   332  	return retval
   333  }
   334  
   335  // getValidationOptions returns the validation options to be
   336  // compatible with the specified version and existing CSR.
   337  // oldCSR may be nil if this is a create request.
   338  // validation options related to subresource-specific capabilities are set to false.
   339  func getValidationOptions(newCSR, oldCSR *certificates.CertificateSigningRequest) certificateValidationOptions {
   340  	return certificateValidationOptions{
   341  		allowResettingCertificate:    false,
   342  		allowBothApprovedAndDenied:   allowBothApprovedAndDenied(oldCSR),
   343  		allowLegacySignerName:        allowLegacySignerName(oldCSR),
   344  		allowDuplicateConditionTypes: allowDuplicateConditionTypes(oldCSR),
   345  		allowEmptyConditionType:      allowEmptyConditionType(oldCSR),
   346  		allowArbitraryCertificate:    allowArbitraryCertificate(newCSR, oldCSR),
   347  		allowDuplicateUsages:         allowDuplicateUsages(oldCSR),
   348  		allowUnknownUsages:           allowUnknownUsages(oldCSR),
   349  	}
   350  }
   351  
   352  func allowBothApprovedAndDenied(oldCSR *certificates.CertificateSigningRequest) bool {
   353  	if oldCSR == nil {
   354  		return false
   355  	}
   356  	approved := false
   357  	denied := false
   358  	for _, c := range oldCSR.Status.Conditions {
   359  		if c.Type == certificates.CertificateApproved {
   360  			approved = true
   361  		} else if c.Type == certificates.CertificateDenied {
   362  			denied = true
   363  		}
   364  	}
   365  	// compatibility with existing data
   366  	return approved && denied
   367  }
   368  
   369  func allowLegacySignerName(oldCSR *certificates.CertificateSigningRequest) bool {
   370  	switch {
   371  	case oldCSR != nil && oldCSR.Spec.SignerName == certificates.LegacyUnknownSignerName:
   372  		return true // compatibility with existing data
   373  	default:
   374  		return false
   375  	}
   376  }
   377  
   378  func allowDuplicateConditionTypes(oldCSR *certificates.CertificateSigningRequest) bool {
   379  	switch {
   380  	case oldCSR != nil && hasDuplicateConditionTypes(oldCSR):
   381  		return true // compatibility with existing data
   382  	default:
   383  		return false
   384  	}
   385  }
   386  func hasDuplicateConditionTypes(csr *certificates.CertificateSigningRequest) bool {
   387  	seen := map[certificates.RequestConditionType]bool{}
   388  	for _, c := range csr.Status.Conditions {
   389  		if seen[c.Type] {
   390  			return true
   391  		}
   392  		seen[c.Type] = true
   393  	}
   394  	return false
   395  }
   396  
   397  func allowEmptyConditionType(oldCSR *certificates.CertificateSigningRequest) bool {
   398  	switch {
   399  	case oldCSR != nil && hasEmptyConditionType(oldCSR):
   400  		return true // compatibility with existing data
   401  	default:
   402  		return false
   403  	}
   404  }
   405  func hasEmptyConditionType(csr *certificates.CertificateSigningRequest) bool {
   406  	for _, c := range csr.Status.Conditions {
   407  		if len(c.Type) == 0 {
   408  			return true
   409  		}
   410  	}
   411  	return false
   412  }
   413  
   414  func allowArbitraryCertificate(newCSR, oldCSR *certificates.CertificateSigningRequest) bool {
   415  	switch {
   416  	case newCSR != nil && oldCSR != nil && bytes.Equal(newCSR.Status.Certificate, oldCSR.Status.Certificate):
   417  		return true // tolerate updates that don't touch status.certificate
   418  	case oldCSR != nil && validateCertificate(oldCSR.Status.Certificate) != nil:
   419  		return true // compatibility with existing data
   420  	default:
   421  		return false
   422  	}
   423  }
   424  
   425  func allowUnknownUsages(oldCSR *certificates.CertificateSigningRequest) bool {
   426  	switch {
   427  	case oldCSR != nil && hasUnknownUsage(oldCSR.Spec.Usages):
   428  		return true // compatibility with existing data
   429  	default:
   430  		return false
   431  	}
   432  }
   433  
   434  func hasUnknownUsage(usages []certificates.KeyUsage) bool {
   435  	for _, usage := range usages {
   436  		if !allValidUsages.Has(string(usage)) {
   437  			return true
   438  		}
   439  	}
   440  	return false
   441  }
   442  
   443  func allowDuplicateUsages(oldCSR *certificates.CertificateSigningRequest) bool {
   444  	switch {
   445  	case oldCSR != nil && hasDuplicateUsage(oldCSR.Spec.Usages):
   446  		return true // compatibility with existing data
   447  	default:
   448  		return false
   449  	}
   450  }
   451  
   452  func hasDuplicateUsage(usages []certificates.KeyUsage) bool {
   453  	seen := make(map[certificates.KeyUsage]bool, len(usages))
   454  	for _, usage := range usages {
   455  		if seen[usage] {
   456  			return true
   457  		}
   458  		seen[usage] = true
   459  	}
   460  	return false
   461  }
   462  
   463  type ValidateClusterTrustBundleOptions struct {
   464  	SuppressBundleParsing bool
   465  }
   466  
   467  // ValidateClusterTrustBundle runs all validation checks on bundle.
   468  func ValidateClusterTrustBundle(bundle *certificates.ClusterTrustBundle, opts ValidateClusterTrustBundleOptions) field.ErrorList {
   469  	var allErrors field.ErrorList
   470  
   471  	metaErrors := apivalidation.ValidateObjectMeta(&bundle.ObjectMeta, false, apivalidation.ValidateClusterTrustBundleName(bundle.Spec.SignerName), field.NewPath("metadata"))
   472  	allErrors = append(allErrors, metaErrors...)
   473  
   474  	if bundle.Spec.SignerName != "" {
   475  		signerNameErrors := apivalidation.ValidateSignerName(field.NewPath("spec", "signerName"), bundle.Spec.SignerName)
   476  		allErrors = append(allErrors, signerNameErrors...)
   477  	}
   478  
   479  	if !opts.SuppressBundleParsing {
   480  		pemErrors := validateTrustBundle(field.NewPath("spec", "trustBundle"), bundle.Spec.TrustBundle)
   481  		allErrors = append(allErrors, pemErrors...)
   482  	}
   483  
   484  	return allErrors
   485  }
   486  
   487  // ValidateClusterTrustBundleUpdate runs all update validation checks on an
   488  // update.
   489  func ValidateClusterTrustBundleUpdate(newBundle, oldBundle *certificates.ClusterTrustBundle) field.ErrorList {
   490  	// If the caller isn't changing the TrustBundle field, don't parse it.
   491  	// This helps smoothly handle changes in Go's PEM or X.509 parsing
   492  	// libraries.
   493  	opts := ValidateClusterTrustBundleOptions{}
   494  	if newBundle.Spec.TrustBundle == oldBundle.Spec.TrustBundle {
   495  		opts.SuppressBundleParsing = true
   496  	}
   497  
   498  	var allErrors field.ErrorList
   499  	allErrors = append(allErrors, ValidateClusterTrustBundle(newBundle, opts)...)
   500  	allErrors = append(allErrors, apivalidation.ValidateObjectMetaUpdate(&newBundle.ObjectMeta, &oldBundle.ObjectMeta, field.NewPath("metadata"))...)
   501  	allErrors = append(allErrors, apivalidation.ValidateImmutableField(newBundle.Spec.SignerName, oldBundle.Spec.SignerName, field.NewPath("spec", "signerName"))...)
   502  	return allErrors
   503  }
   504  
   505  // validateTrustBundle rejects intra-block headers, blocks
   506  // that don't parse as X.509 CA certificates, and duplicate trust anchors.  It
   507  // requires that at least one trust anchor is provided.
   508  func validateTrustBundle(path *field.Path, in string) field.ErrorList {
   509  	var allErrors field.ErrorList
   510  
   511  	if len(in) > certificates.MaxTrustBundleSize {
   512  		allErrors = append(allErrors, field.TooLong(path, fmt.Sprintf("<value omitted, len %d>", len(in)), certificates.MaxTrustBundleSize))
   513  		return allErrors
   514  	}
   515  
   516  	blockDedupe := map[string][]int{}
   517  
   518  	rest := []byte(in)
   519  	var b *pem.Block
   520  	i := -1
   521  	for {
   522  		b, rest = pem.Decode(rest)
   523  		if b == nil {
   524  			break
   525  		}
   526  		i++
   527  
   528  		if b.Type != "CERTIFICATE" {
   529  			allErrors = append(allErrors, field.Invalid(path, "<value omitted>", fmt.Sprintf("entry %d has bad block type: %v", i, b.Type)))
   530  			continue
   531  		}
   532  
   533  		if len(b.Headers) != 0 {
   534  			allErrors = append(allErrors, field.Invalid(path, "<value omitted>", fmt.Sprintf("entry %d has PEM block headers", i)))
   535  			continue
   536  		}
   537  
   538  		cert, err := x509.ParseCertificate(b.Bytes)
   539  		if err != nil {
   540  			allErrors = append(allErrors, field.Invalid(path, "<value omitted>", fmt.Sprintf("entry %d does not parse as X.509", i)))
   541  			continue
   542  		}
   543  
   544  		if !cert.IsCA {
   545  			allErrors = append(allErrors, field.Invalid(path, "<value omitted>", fmt.Sprintf("entry %d does not have the CA bit set", i)))
   546  			continue
   547  		}
   548  
   549  		if !cert.BasicConstraintsValid {
   550  			allErrors = append(allErrors, field.Invalid(path, "<value omitted>", fmt.Sprintf("entry %d has invalid basic constraints", i)))
   551  			continue
   552  		}
   553  
   554  		blockDedupe[string(b.Bytes)] = append(blockDedupe[string(b.Bytes)], i)
   555  	}
   556  
   557  	// If we had a malformed block, don't also output potentially-redundant
   558  	// errors about duplicate or missing trust anchors.
   559  	if len(allErrors) != 0 {
   560  		return allErrors
   561  	}
   562  
   563  	if len(blockDedupe) == 0 {
   564  		allErrors = append(allErrors, field.Invalid(path, "<value omitted>", "at least one trust anchor must be provided"))
   565  	}
   566  
   567  	for _, indices := range blockDedupe {
   568  		if len(indices) > 1 {
   569  			allErrors = append(allErrors, field.Invalid(path, "<value omitted>", fmt.Sprintf("duplicate trust anchor (indices %v)", indices)))
   570  		}
   571  	}
   572  
   573  	return allErrors
   574  }