grpc/grpc-java · error · ResourceInvalidException

verify_certificate_hash in default_validation_context is not

Error message

verify_certificate_hash in default_validation_context is not supported

What it means

gRPC xDS rejects a CertificateValidationContext whose default_validation_context contains verify_certificate_hash entries. Certificate-hash (SHA256 fingerprint) pinning is not supported by grpc-java's xDS transport security, so any cluster resource carrying it fails validation with ResourceInvalidException.

Source

Thrown at xds/src/main/java/io/grpc/xds/XdsClusterResource.java:515

        certificateValidationContext = commonTlsContext.getValidationContext();
      } else if (commonTlsContext.hasCombinedValidationContext() && commonTlsContext
          .getCombinedValidationContext().hasDefaultValidationContext()) {
        certificateValidationContext = commonTlsContext.getCombinedValidationContext()
            .getDefaultValidationContext();
      }
      if (certificateValidationContext != null) {
        @SuppressWarnings("deprecation") // gRFC A29 predates match_typed_subject_alt_names
        int matchSubjectAltNamesCount = certificateValidationContext.getMatchSubjectAltNamesCount();
        if (matchSubjectAltNamesCount > 0 && server) {
          throw new ResourceInvalidException(
              "match_subject_alt_names only allowed in upstream_tls_context");
        }
        if (certificateValidationContext.getVerifyCertificateSpkiCount() > 0) {
          throw new ResourceInvalidException(
              "verify_certificate_spki in default_validation_context is not supported");
        }
        if (certificateValidationContext.getVerifyCertificateHashCount() > 0) {
          throw new ResourceInvalidException(
              "verify_certificate_hash in default_validation_context is not supported");
        }
        if (certificateValidationContext.hasRequireSignedCertificateTimestamp()) {
          throw new ResourceInvalidException(
              "require_signed_certificate_timestamp in default_validation_context is not "
                  + "supported");
        }
        if (certificateValidationContext.hasCrl()) {
          throw new ResourceInvalidException("crl in default_validation_context is not supported");
        }
        if (certificateValidationContext.hasCustomValidatorConfig()) {
          throw new ResourceInvalidException(
              "custom_validator_config in default_validation_context is not supported");
        }
      }
    }
  }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Remove verify_certificate_hash from default_validation_context
  2. Rely on root-of-trust validation via trust_ca / ca_certificate_provider_file
  3. Constrain server identity with match_subject_alt_names (allowed upstream only)
  4. Use SDS with proper cert validation rather than static fingerprints

Example fix

// before
default_validation_context {
  verify_certificate_hash: "aabbcc..."
}
// after
default_validation_context {}
trust_ca { ... }
match_subject_alt_names { prefix: "expected.name" }
Defensive patterns

Strategy: validation

Validate before calling

if (ctx.getDefaultValidationContext().getVerifyCertificateHashCount() > 0) {
  throw new IllegalArgumentException("verify_certificate_hash unsupported by grpc-java xDS");
}

Try / catch

try {
  cluster = XdsClusterResource.parse(resource);
} catch (ResourceInvalidException e) {
  // fall back to last-known-good cluster config
}

Prevention

When it happens

Trigger: A CDS Cluster resource's upstream_tls_context -> common_tls_context -> validation_context.default_validation_context sets verify_certificate_hash (one or more cert fingerprints), reaching validateCommonTlsContext via validateUpstreamTlsContext.

Common situations: Porting Envoy TLS configs that pin server certificates by hash; security teams adding fingerprint pinning per policy; generated control-plane configs that include hash pins unconditionally.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/55c853418349560a. Report an issue: GitHub.