[java-idp-plugin-oidc-op-oidfed] 02/02: Improved and harmonised the trust chain signature verification logic

Henri Mikkonen henri.mikkonen at iki.fi
Fri Oct 31 14:21:55 UTC 2025


This is an automated email from the git hooks/post-receive script.

hjmikkon pushed a commit to branch main
in repository java-idp-plugin-oidc-op-oidfed.

View the commit online:
https://git.shibboleth.net/view/?p=java-idp-plugin-oidc-op-oidfed.git;a=commit;h=ed95f10f1c4019f9f7c85cdffc2174ef1070a324

commit ed95f10f1c4019f9f7c85cdffc2174ef1070a324
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Oct 31 16:21:25 2025 +0200

    Improved and harmonised the trust chain signature verification logic
    
    The same function is used for validating provided and resolved trust chains
    - DefaultTrustChainSignatureValidationFilterStrategy, removed obsolete DefaultTrustAnchorSignatureValidationFilterStrategy
      - The new one also validates the entity statement signatures with the public key found from the next statement in the chain
      - Draft 10.2: "For each j = 0,...,i-1, verify that the signature of ES[j] validates with a public key in ES[j+1]["jwks"]."
    - Improved testing
---
 ...actTrustEngineSignatureValidationComponent.java |   7 +-
 ...yloadSignatureValidationCredentialResolver.java |  78 ++++++++++++++++
 ...efaultProvidedTrustChainValidationStrategy.java |  58 ++++--------
 ...ustChainSignatureValidationFilterStrategy.java} |  38 ++++++--
 ...ignatureValidationKeyContainerJwtCriterion.java | 101 +++++++++++++++++++++
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  12 ++-
 .../idp/flows/oidfed/register/register-beans.xml   |  33 +++++--
 .../flow/oidfed/AbstractFederationFlowTest.java    |  35 ++++++-
 .../AuthorizeFlowAutomaticRegistrationTest.java    |  19 ++++
 .../profile/flow/oidfed/RegistrationFlowTest.java  |  25 +++--
 .../profile/flow/oidfed/ResolveEntityFlowTest.java |  11 +++
 .../UserInfoFlowAutomaticRegistrationTest.java     |   8 +-
 12 files changed, 349 insertions(+), 76 deletions(-)

diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractTrustEngineSignatureValidationComponent.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractTrustEngineSignatureValidationComponent.java
index 73ec509..463dcf9 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractTrustEngineSignatureValidationComponent.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/AbstractTrustEngineSignatureValidationComponent.java
@@ -14,6 +14,8 @@
 
 package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
 
+import java.text.ParseException;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
@@ -91,10 +93,11 @@ public class AbstractTrustEngineSignatureValidationComponent extends AbstractIde
                 log.debug("Successfully validated entity statement for {}", entityId);
                 return true;
             }
-        } catch (final SecurityException e) {
+            log.warn("Trust Engine validation failed for {}, issued by {}", entityId,
+                    jwt.getJWTClaimsSet().getIssuer());
+        } catch (final SecurityException | ParseException e) {
             log.debug("Could not validate entity statement for {}", entityId, e);
         }
-        log.warn("Trust Engine validation failed for {}", entityId);
         return false;
     }
 }
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultPayloadSignatureValidationCredentialResolver.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultPayloadSignatureValidationCredentialResolver.java
new file mode 100644
index 0000000..af1ad36
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultPayloadSignatureValidationCredentialResolver.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+
+import java.text.ParseException;
+import java.util.Map;
+import java.util.Objects;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+import org.slf4j.Logger;
+
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.oidc.security.credential.impl.BasicJOSEObjectCredentialResolver;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.ResolverException;
+
+/**
+ * Resolves credentials from the jwks-claim located in the signed JWT (entity statement) payload. The JWT is fetched
+ * via {@link SignatureValidationKeyContainerJwtCriterion}.
+ */
+public class DefaultPayloadSignatureValidationCredentialResolver extends BasicJOSEObjectCredentialResolver {
+
+    /** Logger. */
+    @Nonnull
+    private final Logger log = LoggerFactory.getLogger(DefaultPayloadSignatureValidationCredentialResolver.class);
+
+    /** {@inheritDoc} */
+    @Override
+    protected Iterable<Credential> resolveFromSource(@Nullable final CriteriaSet criteriaSet) throws ResolverException {
+        if (criteriaSet == null || !criteriaSet.contains(SignatureValidationKeyContainerJwtCriterion.class)) {
+            throw new ResolverException("CriteriaSet does not contain SignatureValidationKeyContainerJwtCriterion");
+        }
+
+        final SignatureValidationKeyContainerJwtCriterion keyContainer =
+                criteriaSet.get(SignatureValidationKeyContainerJwtCriterion.class);
+        final SignedJWT jwt = keyContainer.getJwt();
+        if (jwt == null) {
+            throw new ResolverException(
+                    "SignatureValidationKeyContainerJwtCriterion did not contain an instance of SignedJWT");
+        }
+        try {
+            final Map<String, Object> rawJwks = jwt.getJWTClaimsSet().getJSONObjectClaim("jwks");
+            if (rawJwks == null || rawJwks.isEmpty()) {
+                log.debug("No jwks found from the payload");
+                return CollectionSupport.emptyList();
+            }
+            final JWKSet jwks = JWKSet.parse(rawJwks);
+            return jwks.getKeys().stream()
+                    .filter(Objects::nonNull)
+                    .map(jwk -> buildJWKCredential(jwk, null))
+                    .filter(Objects::nonNull)
+                    .map(Credential.class::cast)
+                    .toList();
+        } catch (final ParseException e) {
+            throw new ResolverException("Could not parse JWKSet from JOSEObject", e);
+        }
+    }
+
+}
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultProvidedTrustChainValidationStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultProvidedTrustChainValidationStrategy.java
index cd48e81..0bd362a 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultProvidedTrustChainValidationStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultProvidedTrustChainValidationStrategy.java
@@ -23,7 +23,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.security.trust.TrustEngine;
 import org.slf4j.Logger;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,25 +32,24 @@ import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationP
 import net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.constraints.FederationPolicyConstraintHelper;
 import net.shibboleth.oidc.metadata.filter.MetadataFilterContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.shared.resolver.CriteriaSet;
 
 /**
- * Default strategy for validating provided trust chain signatures via {@link TrustEngine} and configurable
- * trust anchor signature validation filter.
+ * Default strategy for validating provided trust chain signatures via configurable signature validation filter and
+ * applying the constraints.
  */
-public class DefaultProvidedTrustChainValidationStrategy
-    extends AbstractEntityStatementSignatureValidationComponent 
+public class DefaultProvidedTrustChainValidationStrategy extends AbstractIdentifiableInitializableComponent 
     implements BiPredicate<ProfileRequestContext, List<EntityStatement>> {
 
     /** Class logger. */
     @Nonnull private Logger log = LoggerFactory.getLogger(DefaultProvidedTrustChainValidationStrategy.class);
 
     /** Strategy for validating trust anchor's entity configuration signature. */
-    @NonnullAfterInit BiFunction<EntityStatement, MetadataFilterContext, EntityStatement>
-        trustAnchorSignatureValidationFilterStrategy;
+    @NonnullAfterInit BiFunction<List<List<EntityStatement>>, MetadataFilterContext, List<List<EntityStatement>>>
+        trustChainSignatureValidationFilterStrategy;
 
     /** Map of supported federation policy constraints. */
     @NonnullAfterInit private Map<String, FederationPolicyConstraint> federationPolicyConstraints;
@@ -60,15 +58,15 @@ public class DefaultProvidedTrustChainValidationStrategy
     @NonnullAfterInit private ObjectMapper objectMapper;
 
     /**
-     * Set the strategy for validating trust anchor's entity configuration signature.
+     * Set the strategy for validating trust chain signatures.
      * 
      * @param strategy validation strategy
      */
-    public void setTrustAnchorSignatureValidationFilterStrategy(
-            @Nonnull final BiFunction<EntityStatement, MetadataFilterContext, EntityStatement> strategy) {
+    public void setTrustChainSignatureValidationFilterStrategy(
+            @Nonnull final BiFunction<List<List<EntityStatement>>, MetadataFilterContext, List<List<EntityStatement>>> strategy) {
         checkSetterPreconditions();
-        trustAnchorSignatureValidationFilterStrategy = Constraint.isNotNull(strategy,
-                "TrustAnchorSignatureValidationFilterStrategy cannot be null");
+        trustChainSignatureValidationFilterStrategy = Constraint.isNotNull(strategy,
+                "TrustChainSignatureValidationFilterStrategy cannot be null");
     }
 
     /**
@@ -96,8 +94,8 @@ public class DefaultProvidedTrustChainValidationStrategy
     @Override
     protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
-        if (trustAnchorSignatureValidationFilterStrategy == null) {
-            throw new ComponentInitializationException("TrustAnchorSignatureValidationFilterStrategy cannot be null");
+        if (trustChainSignatureValidationFilterStrategy == null) {
+            throw new ComponentInitializationException("TrustChainSignatureValidationFilterStrategy cannot be null");
         }
         if (federationPolicyConstraints == null) {
             throw new ComponentInitializationException("Map of policy constraints cannot be null");
@@ -117,28 +115,12 @@ public class DefaultProvidedTrustChainValidationStrategy
             return false;
         }
 
-        final EntityStatement entityConfiguration = trustChain.get(0);
-        assert entityConfiguration != null;
-        if (!validateStatement(entityConfiguration,
-                new CriteriaSet(new SubjectEntityStatementCriterion(entityConfiguration)),
-                entityConfiguration.getEntityID().getValue())) {
-            log.debug("Entity configuration signature validation failed");
+        final List<List<EntityStatement>> validatedChains =
+                trustChainSignatureValidationFilterStrategy.apply(List.of(trustChain), null);
+        if (validatedChains == null || validatedChains.size() != 1) {
+            log.debug("The trust chain did not pass the signature validation");
             return false;
         }
-        for (int i = 1; i < trustChain.size() - 2; i++) {
-            final EntityStatement subordinateStatement = trustChain.get(i);
-            final EntityStatement issuerStatement = trustChain.get(i + 1);
-            assert subordinateStatement != null;
-            assert issuerStatement != null;
-            final CriteriaSet criteria = new CriteriaSet();
-            criteria.add(new IssuerEntityStatementCriterion(issuerStatement));
-            criteria.add(new SubjectEntityStatementCriterion(subordinateStatement));
-            if (!validateStatement(subordinateStatement, criteria, subordinateStatement.getEntityID().getValue())) {
-                log.debug("Subordinate statement {} signature validation failed", subordinateStatement.getEntityID());
-                return false;
-            }
-        }
-
         for (int i = 1; i < trustChain.size() - 1; i++) {
             if (!FederationPolicyConstraintHelper.verifyPolicyConstraints(
                     objectMapper, trustChain.get(i), trustChain.subList(0, i), federationPolicyConstraints)) {
@@ -148,12 +130,6 @@ public class DefaultProvidedTrustChainValidationStrategy
             }
         }
 
-        final EntityStatement trustAnchor = trustChain.get(trustChain.size() - 1);
-        if (!trustAnchor.equals(trustAnchorSignatureValidationFilterStrategy.apply(trustAnchor, null))) {
-            log.debug("Trust anchor {} validation failed", trustAnchor.getEntityID());
-            return false;
-        }
-
         return true;
     }
 }
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustAnchorSignatureValidationFilterStrategy.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustChainSignatureValidationFilterStrategy.java
similarity index 61%
rename from idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustAnchorSignatureValidationFilterStrategy.java
rename to idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustChainSignatureValidationFilterStrategy.java
index b07d2c9..71ee250 100644
--- a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustAnchorSignatureValidationFilterStrategy.java
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/DefaultTrustChainSignatureValidationFilterStrategy.java
@@ -21,30 +21,39 @@ import java.util.function.BiFunction;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.opensaml.security.trust.TrustEngine;
 import org.slf4j.Logger;
 
+import com.nimbusds.jwt.SignedJWT;
 import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
 
 import net.shibboleth.oidc.metadata.filter.MetadataFilterContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
-import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
 
 /**
- * Default signature validating filter trust chains. The signature validation is performed by passing the trust anchor
- * entity statement of each trust chain to the configurable validation filter strategy. All the chains whose anchor
- * doesn't pass the validation are filtered out from the result.
+ * Default signature validating filter for trust chains. The signature for each entity statement within trust chain is
+ * verified by using the contents of the jwks-claim of the payload of the next entity statement in the chain until the
+ * final subordinate statement of the chain. The configurable {@link TrustEngine} is used for validating the signature.
+ * The trust engine is fed with the JWT to be verified and the {@link SignatureValidationKeyContainerJwtCriterion}
+ * containing the JWT with the keyset used for validation.
+ * 
+ * The trust anchor signature validation is performed by passing the trust anchor entity statement of each trust chain
+ * to the configurable validation filter strategy.
+ * 
+ * All the chains that don't pass the full validation are filtered out from the result.
  */
 @ThreadSafeAfterInit
-public class DefaultTrustAnchorSignatureValidationFilterStrategy extends AbstractIdentifiableInitializableComponent
+public class DefaultTrustChainSignatureValidationFilterStrategy extends AbstractTrustEngineSignatureValidationComponent
         implements BiFunction<List<List<EntityStatement>>, MetadataFilterContext, List<List<EntityStatement>>> {
 
     /** Class logger. */
     @Nonnull private Logger log =
-            LoggerFactory.getLogger(DefaultTrustAnchorSignatureValidationFilterStrategy.class);
+            LoggerFactory.getLogger(DefaultTrustChainSignatureValidationFilterStrategy.class);
 
     /** Signature validation filter strategy for trust anchor entity statements. */
     @NonnullAfterInit private BiFunction<EntityStatement, MetadataFilterContext, EntityStatement>
@@ -82,7 +91,22 @@ public class DefaultTrustAnchorSignatureValidationFilterStrategy extends Abstrac
         }
 
         final List<List<EntityStatement>> result = new ArrayList<>();
-        for (final List<EntityStatement> trustChain : trustChains) {
+        trustChainLoop: for (final List<EntityStatement> trustChain : trustChains) {
+            for (int i = 0; i < trustChain.size() - 1; i++) {
+                final EntityStatement trustChainEntry = trustChain.get(i);
+                final SignedJWT keyContainer = trustChain.get(i + 1).getSignedStatement();
+                final CriteriaSet criteria =
+                        new CriteriaSet(new SignatureValidationKeyContainerJwtCriterion(keyContainer));
+                if (!validateJwt(trustChainEntry.getSignedStatement(), criteria,
+                        trustChain.get(i).getEntityID().getValue())) {
+                    log.warn("The signature check for {} failed, ignoring trust chain anchored by {}",
+                            i == 0 ? "leaf entity configuration" : "subordinate statement",
+                                    trustChain.get(trustChain.size() - 1).getEntityID().getValue());
+                    log.trace("Key container {} could not validate the trust chain entry {}", keyContainer.serialize(),
+                            trustChainEntry.getSignedStatement().serialize());
+                    continue trustChainLoop;
+                }
+            }
             final EntityStatement trustAnchorStatement = trustChain.get(trustChain.size() - 1);
             final String entityId = trustAnchorStatement.getEntityID().getValue();
             final EntityStatement filteredStatement =
diff --git a/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/SignatureValidationKeyContainerJwtCriterion.java b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/SignatureValidationKeyContainerJwtCriterion.java
new file mode 100644
index 0000000..c1018c4
--- /dev/null
+++ b/idp-oidfed-op-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oidfed/metadata/SignatureValidationKeyContainerJwtCriterion.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.oidc.op.oidfed.metadata;
+
+import java.util.Objects;
+
+import javax.annotation.Nullable;
+
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.shared.resolver.Criterion;
+
+/**
+ * An implementation of {@link Criterion} which specifies criteria based on the contents of a {@link SignedJWT} element
+ * containing signature validation keys.
+ */
+public final class SignatureValidationKeyContainerJwtCriterion implements Criterion {
+    
+    /** The JWT which serves as the source for credential criteria. */
+    @Nullable private SignedJWT jwt;
+    
+    /**
+     * Constructor.
+     *
+     * @param keyContainer the key container criteria to use
+     */
+    public SignatureValidationKeyContainerJwtCriterion(@Nullable final SignedJWT keyContainer) {
+       setJwt(keyContainer);
+    }
+
+    /**
+     * Gets the JWT which is the source of credential criteria.
+     * 
+     * @return the JWT credential criteria
+     */
+    @Nullable public SignedJWT getJwt() {
+        return jwt;
+    }
+    
+    /**
+     * Sets the JWT which is the source of credential criteria.
+     * 
+     * @param keyContainer the key container criteria to use
+     * 
+     */
+    public void setJwt(@Nullable final SignedJWT keyContainer) {
+        // Note: we allow JOSEObject to be null to handle case where application context,
+        // other accompanying criteria, etc should be used to resolve credentials.
+        jwt = keyContainer;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("SignatureValidationKeyContainerJwtCriterion [jwt=");
+        builder.append("<contents not displayable>");
+        builder.append("]");
+        return builder.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        if (jwt != null) {
+            return jwt.hashCode();
+        }
+        return super.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof SignatureValidationKeyContainerJwtCriterion other) {
+            return Objects.equals(jwt, other.jwt);
+        }
+
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 43dd825..020249d 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -184,7 +184,17 @@
             <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustChainExpirationTimeStrategy"/>
         </property>
         <property name="metadataFilterStrategy">
-            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustAnchorSignatureValidationFilterStrategy">
+            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustChainSignatureValidationFilterStrategy">
+                <property name="trustEngine">
+                    <bean class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine">
+                        <constructor-arg index="0">
+                            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultPayloadSignatureValidationCredentialResolver" />
+                        </constructor-arg>
+                        <constructor-arg index="1">
+                            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultPayloadJOSEObjectCredentialResolver" />
+                        </constructor-arg>
+                    </bean>
+                </property>
                 <property name="entityStatementSignatureValidationFilterStrategy">
                     <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultEntityStatementSignatureValidationFilterStrategy">
                         <property name="trustEngine">
diff --git a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
index bfcdba0..0781d06 100644
--- a/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
+++ b/idp-oidfed-op-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidfed/register/register-beans.xml
@@ -47,19 +47,32 @@
         <property name="providedTrustChainValidationStrategy">
             <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultProvidedTrustChainValidationStrategy"
                 p:federationPolicyConstraints-ref="%{idp.oidfed.FederationPolicyConstraints:shibboleth.oidfed.DefaultFederationPolicyConstraints}"
-                p:objectMapper-ref="shibboleth.oidfed.policy.JSONObjectMapper"
-                p:trustEngine-ref="shibboleth.oidfed.DefaultEntityConfigurationTrustEngine">
-                <property name="trustAnchorSignatureValidationFilterStrategy">
-                    <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultEntityStatementSignatureValidationFilterStrategy">
+                p:objectMapper-ref="shibboleth.oidfed.policy.JSONObjectMapper">
+                <property name="trustChainSignatureValidationFilterStrategy">
+                    <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultTrustChainSignatureValidationFilterStrategy">
                         <property name="trustEngine">
                             <bean class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine">
                                 <constructor-arg index="0">
-                                    <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultLocalTrustAnchorCredentialResolver"
-                                        c:cache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache" />
-                                 </constructor-arg>
-                                 <constructor-arg index="1">
-                                     <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultPayloadJOSEObjectCredentialResolver" />
-                                 </constructor-arg>
+                                    <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultPayloadSignatureValidationCredentialResolver" />
+                                </constructor-arg>
+                                <constructor-arg index="1">
+                                    <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultPayloadJOSEObjectCredentialResolver" />
+                                </constructor-arg>
+                            </bean>
+                        </property>
+                        <property name="entityStatementSignatureValidationFilterStrategy">
+                            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultEntityStatementSignatureValidationFilterStrategy">
+                                <property name="trustEngine">
+                                    <bean class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine">
+                                        <constructor-arg index="0">
+                                            <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultLocalTrustAnchorCredentialResolver"
+                                                c:cache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache" />
+                                         </constructor-arg>
+                                         <constructor-arg index="1">
+                                             <bean class="net.shibboleth.idp.plugin.oidc.op.oidfed.metadata.DefaultPayloadJOSEObjectCredentialResolver" />
+                                         </constructor-arg>
+                                    </bean>
+                                </property>
                             </bean>
                         </property>
                     </bean>
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java
index eaa0934..68b83a4 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AbstractFederationFlowTest.java
@@ -228,13 +228,22 @@ public class AbstractFederationFlowTest extends AbstractOidcFlowTest {
         return rpEntityConfiguration(clientId, metadata, authorityHints);
     }
 
+    protected String rpEntityConfiguration(final String clientId, final JWK leafKey,
+            final String... authorityHints) throws URISyntaxException {
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setRedirectionURI(new URI(redirectUri));
+        metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
+        return rpEntityConfiguration(clientId, metadata, null, leafKey, authorityHints);
+    }
+
     protected String rpEntityConfiguration(final String clientId, final OIDCClientMetadata metadata,
             final String... authorityHints) throws URISyntaxException {
-        return rpEntityConfiguration(clientId, metadata, null, authorityHints);
+        return rpEntityConfiguration(clientId, metadata, null, leafKey, authorityHints);
     }
 
     protected String rpEntityConfiguration(final String clientId, final OIDCClientMetadata metadata,
-            final List<Map<String, String>> trustMarks, final String... authorityHints) throws URISyntaxException {
+            final List<Map<String, String>> trustMarks, final JWK leafKey, final String... authorityHints)
+                    throws URISyntaxException {
         final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().issuer(clientId).subject(clientId)
                 .issueTime(Date.from(Instant.now()))
                 .expirationTime(Date.from(Instant.now().plusSeconds(300)))
@@ -359,10 +368,15 @@ public class AbstractFederationFlowTest extends AbstractOidcFlowTest {
     }
 
     protected String subordinateStatement(final String issuer, final Map<String, Object> metadata) {
+        return subordinateStatement(issuer, metadata, leafKey);
+    }
+
+    protected String subordinateStatement(final String issuer, final Map<String, Object> metadata,
+            final JWK subjectKey) {
         final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder().issuer(anchorId).subject(issuer)
                 .issueTime(Date.from(Instant.now()))
                 .expirationTime(Date.from(Instant.now().plusSeconds(300)))
-                .claim("jwks", new JWKSet(leafKey).toJSONObject(true))
+                .claim("jwks", new JWKSet(subjectKey).toJSONObject(true))
                 .claim("metadata", metadata)
                 .claim("authority_hints", new String[] { anchorId })
                 .build();
@@ -449,6 +463,19 @@ public class AbstractFederationFlowTest extends AbstractOidcFlowTest {
         }
     }
 
+    protected void rpConfigureMockHttpClient(final String clientId, final JWK leafKey) {
+        try {
+            mapResponse(entityConfigurationUrl(clientId),
+                    mockResponse(rpEntityConfiguration(clientId, leafKey)));
+            mapResponse(entityConfigurationUrl(anchorId), mockResponse(trustedAnchorConfiguration()));
+            mapResponse(subordinateStatementUrl(anchorFetchEndpoint, clientId),
+                    mockResponse(subordinateStatement(clientId, Map.of("openid_relying_party",
+                            new OIDCClientMetadata().toJSONObject()))));
+        } catch (UnsupportedOperationException | IOException | URISyntaxException e) {
+            Assert.fail("Could not initialize mock HTTP client", e);
+        }
+    }
+
     protected void rpConfigureMockHttpClient(final String clientId, final OIDCClientMetadata metadata) {
         try {
             mapResponse(entityConfigurationUrl(clientId), mockResponse(rpEntityConfiguration(clientId, metadata)));
@@ -547,7 +574,7 @@ public class AbstractFederationFlowTest extends AbstractOidcFlowTest {
                     mockResponse(rpSubordinateStatement(anchorId, trustedAnchorKey, intermediateKey, intermediateId,
                             Map.of("openid_relying_party", (Map<String, Object>) testVector.get("TA")), anchorId)));
             mapResponse(subordinateStatementUrl(intermediateId + "/fetch", clientId),
-                    mockResponse(rpSubordinateStatement(intermediateId, intermediateKey, rpKey, clientId,
+                    mockResponse(rpSubordinateStatement(intermediateId, intermediateKey, leafKey, clientId,
                             Map.of("openid_relying_party", (Map<String, Object>) testVector.get("INT")),
                             intermediateId)));
         } catch (UnsupportedOperationException | IOException | URISyntaxException | ParseException e) {
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java
index 8e7de38..4ce2b70 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/AuthorizeFlowAutomaticRegistrationTest.java
@@ -19,6 +19,7 @@ import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URLEncoder;
+import java.security.NoSuchAlgorithmException;
 import java.text.ParseException;
 import java.time.Duration;
 import java.time.Instant;
@@ -141,6 +142,24 @@ public class AuthorizeFlowAutomaticRegistrationTest extends AbstractFederationFl
         Assert.assertEquals(unwrapTrustChainFromAuthorizeCode(successResponse), List.of(clientId, anchorId));
     }
 
+    @Test
+    public void testWithInvalidTrustChain_subordinateKeyNotMatchingEntityConfiguration_signedRequestObject()
+            throws IOException, UnsupportedOperationException, URISyntaxException, NoSuchAlgorithmException {
+        final String clientId = uniqueClientId();
+        rpConfigureMockHttpClient(clientId, initializeNewJwk("RSA", 2048, "mockNewLeafKey"));
+        final FlowExecutionResult result =
+                launchAuthenticationRequest(clientId, "openid profile", signedRequestObject(Map.of(
+                        "iss", clientId,
+                        "client_id", clientId,
+                        "aud", issuer,
+                        "exp", Instant.now().plus(Duration.ofMinutes(5)).toEpochMilli(),
+                        "jti", UUID.randomUUID(),
+                        "response_type", "code",
+                        "scope", "openid profile",
+                        "redirect_uri", redirectUri)));
+        Assert.assertEquals(result.getOutcome().getId(), "ErrorView");
+    }
+
     @Test
     public void testWithValidTrustChain_resolveApiFailsNoFaildback_signedRequestObject()
             throws IOException, UnsupportedOperationException, URISyntaxException {
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
index eddf551..e3551ec 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/RegistrationFlowTest.java
@@ -272,7 +272,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
     public void testValidTrustChain_validMaxLengthInAnchor() throws Exception {
         final String clientId = uniqueClientId();
         final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
-                subordinateStatement(anchorId, anchorKey, leafKey, clientId, Collections.emptyMap(),
+                subordinateStatement(anchorId, trustedAnchorKey, leafKey, clientId, Collections.emptyMap(),
                         Map.of("max_path_length", Integer.valueOf(0))) + "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -291,7 +291,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
                 subordinateStatement(intermediateId, intermediateKey, leafKey, clientId, Collections.emptyMap(),
                         Collections.emptyMap()) + "\", \"" +
-                subordinateStatement(anchorId, anchorKey, intermediateKey, intermediateId, Collections.emptyMap(),
+                subordinateStatement(anchorId, trustedAnchorKey, intermediateKey, intermediateId, Collections.emptyMap(),
                         Map.of("max_path_length", Integer.valueOf(0))) + "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -302,7 +302,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
     public void testValidTrustChain_validNamingConstraintInAnchor() throws Exception {
         final String clientId = uniqueClientId();
         final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
-                subordinateStatement(anchorId, anchorKey, leafKey, clientId, Collections.emptyMap(),
+                subordinateStatement(anchorId, trustedAnchorKey, leafKey, clientId, Collections.emptyMap(),
                         Map.of("naming_constraints", Map.of("permitted", List.of(".federation.local")))) +
                 "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
@@ -319,7 +319,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
     public void testValidTrustChain_invalidNamingConstraintInAnchor() throws Exception {
         final String clientId = uniqueClientId();
         final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
-                subordinateStatement(anchorId, anchorKey, leafKey, clientId, Collections.emptyMap(),
+                subordinateStatement(anchorId, trustedAnchorKey, leafKey, clientId, Collections.emptyMap(),
                         Map.of("naming_constraints", Map.of("permitted", List.of(".wrongfederation.local")))) + 
                 "\", \"" + trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
@@ -331,7 +331,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
     public void testValidTrustChain_validEntityTypeInAnchor() throws Exception {
         final String clientId = uniqueClientId();
         final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
-                subordinateStatement(anchorId, anchorKey, leafKey, clientId, Collections.emptyMap(),
+                subordinateStatement(anchorId, trustedAnchorKey, leafKey, clientId, Collections.emptyMap(),
                         Map.of("allowed_entity_types", List.of("openid_relying_party"))) + "\", \""  +
                         trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
@@ -348,7 +348,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
     public void testValidTrustChain_invalidEmptyEntityTypeInAnchor() throws Exception {
         final String clientId = uniqueClientId();
         final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
-                subordinateStatement(anchorId, anchorKey, leafKey, clientId, Collections.emptyMap(),
+                subordinateStatement(anchorId, trustedAnchorKey, leafKey, clientId, Collections.emptyMap(),
                         Map.of("allowed_entity_types", Collections.emptyList())) + "\", \""  +
                         trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
@@ -360,7 +360,7 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
     public void testValidTrustChain_invalidEntityTypeInAnchor() throws Exception {
         final String clientId = uniqueClientId();
         final String trustChain = "[\"" + rpEntityConfiguration(clientId) + "\", \"" +
-                subordinateStatement(anchorId, anchorKey, leafKey, clientId, Collections.emptyMap(),
+                subordinateStatement(anchorId, trustedAnchorKey, leafKey, clientId, Collections.emptyMap(),
                         Map.of("allowed_entity_types", List.of("openid_provider"))) + "\", \""  +
                         trustedAnchorConfiguration() + "\"]";
         setRequest("POST", trustChain, "application/trust-chain+json");
@@ -368,6 +368,17 @@ public class RegistrationFlowTest extends AbstractFederationFlowTest {
         assertErrorCode(result, "invalid_request");
     }
 
+    @Test
+    public void testInvalidTrustChain_subordinateKeyNotMatchingEntityConfiguration() throws Exception {
+        final String clientId = uniqueClientId();
+        final String trustChain = "[\"" + rpEntityConfiguration(clientId, initializeNewJwk("RSA", 2048, "mockNewKey"))
+                + "\", \"" + subordinateStatement(clientId, Map.of("openid_relying_party", 
+                        new OIDCClientMetadata().toJSONObject())) + "\", \"" + trustedAnchorConfiguration() + "\"]";
+        setRequest("POST", trustChain, "application/trust-chain+json");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+    }
+
     @Test
     public void testInvalidTrustChain_wrongRpEntityConfigurationSignerKey() throws Exception {
         final String clientId = uniqueClientId();
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/ResolveEntityFlowTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/ResolveEntityFlowTest.java
index 00551b5..c2049c0 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/ResolveEntityFlowTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/ResolveEntityFlowTest.java
@@ -81,6 +81,17 @@ public class ResolveEntityFlowTest extends AbstractFederationFlowTest {
         Assert.assertNotNull(response.getJWTClaimsSet().getClaim("metadata"));
     }
 
+    @Test
+    public void testRPWithTrustedTrustAnchor_subordinateKeyNotMatchingEntityConfiguration() throws Exception {
+        request.setMethod("GET");
+        final String clientId = uniqueClientId();
+        rpConfigureMockHttpClient(clientId, initializeNewJwk("RSA", 2048, "mockNewLeafKey"));
+        request.setQueryString("sub=" + clientId + "&trust_anchor=" + anchorId + "&entity_type=openid_relying_party");
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertErrorCode(result, "invalid_request");
+        assertErrorDescriptionContains(result, "NoTrustChainsResolved");
+    }
+
     @Test
     public void testRPWithTrustedTrustAnchorInvalidMetadata() throws Exception {
         request.setMethod("GET");
diff --git a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java
index 33b4d69..ec302d1 100644
--- a/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java
+++ b/idp-oidfed-op-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/flow/oidfed/UserInfoFlowAutomaticRegistrationTest.java
@@ -94,7 +94,7 @@ public class UserInfoFlowAutomaticRegistrationTest extends AbstractFederationFlo
         metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
         final String rpEntityConfiguration = rpEntityConfiguration(clientId, metadata, List.of(Map.of(
                 "trust_mark_type", "https://example.org/email-allowing-trust-mark",
-                "trust_mark", trustMark)));
+                "trust_mark", trustMark)), leafKey);
         final String trustAnchorConfiguration = trustedAnchorConfiguration();
         rpConfigureMockHttpClient(clientId, rpEntityConfiguration, trustAnchorConfiguration);
         try {
@@ -102,7 +102,7 @@ public class UserInfoFlowAutomaticRegistrationTest extends AbstractFederationFlo
                     mockResponse(trustMarkIssuerConfiguration(trustMarkIssuerId)));
             mapResponse(subordinateStatementUrl(anchorFetchEndpoint, trustMarkIssuerId),
                     mockResponse(subordinateStatement(trustMarkIssuerId,
-                            Map.of("federation_entity", CollectionSupport.emptyMap()))));
+                            Map.of("federation_entity", CollectionSupport.emptyMap()), trustMarkIssuerKey)));
         } catch (UnsupportedOperationException | IOException e) {
             Assert.fail("Could not initialize mock HTTP client", e);
         }
@@ -142,7 +142,7 @@ public class UserInfoFlowAutomaticRegistrationTest extends AbstractFederationFlo
         final OIDCClientMetadata metadata = new OIDCClientMetadata();
         metadata.setRedirectionURI(URI.create(redirectUri));
         metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
-        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, anchorKey, anchorId,
+        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
                 clientId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
         rpResolveEntityConfigureMockHttpClient(clientId, metadata, List.of(Map.of(
                 "trust_mark_type", "https://example.org/email-allowing-trust-mark",
@@ -164,7 +164,7 @@ public class UserInfoFlowAutomaticRegistrationTest extends AbstractFederationFlo
         final OIDCClientMetadata metadata = new OIDCClientMetadata();
         metadata.setRedirectionURI(URI.create(redirectUri));
         metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
-        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, anchorKey, anchorId,
+        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
                 anchorId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
         rpResolveEntityConfigureMockHttpClient(clientId, metadata, List.of(Map.of(
                 "trust_mark_type", "https://example.org/email-allowing-trust-mark",

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list