001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.openid.connect.sdk.federation.entities;
019
020
021import java.util.*;
022
023import net.minidev.json.JSONArray;
024import net.minidev.json.JSONObject;
025
026import com.nimbusds.jose.jwk.JWKSet;
027import com.nimbusds.jwt.JWTClaimsSet;
028import com.nimbusds.oauth2.sdk.ParseException;
029import com.nimbusds.oauth2.sdk.as.AuthorizationServerMetadata;
030import com.nimbusds.oauth2.sdk.client.ClientMetadata;
031import com.nimbusds.oauth2.sdk.id.Identifier;
032import com.nimbusds.oauth2.sdk.id.Issuer;
033import com.nimbusds.oauth2.sdk.id.Subject;
034import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
035import com.nimbusds.oauth2.sdk.util.MapUtils;
036import com.nimbusds.openid.connect.sdk.federation.policy.MetadataPolicy;
037import com.nimbusds.openid.connect.sdk.federation.policy.language.PolicyViolationException;
038import com.nimbusds.openid.connect.sdk.federation.trust.constraints.TrustChainConstraints;
039import com.nimbusds.openid.connect.sdk.federation.trust.marks.TrustMarkEntry;
040import com.nimbusds.openid.connect.sdk.federation.trust.marks.TrustMarkIssuerMetadata;
041import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
042import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
043
044
045/**
046 * Federation entity statement claims set, serialisable to a JSON object.
047 *
048 * <p>Example claims set:
049 *
050 * <pre>
051 * {
052 *   "iss": "https://feide.no",
053 *   "sub": "https://ntnu.no",
054 *   "iat": 1516239022,
055 *   "exp": 1516298022,
056 *   "crit": ["jti"],
057 *   "jti": "7l2lncFdY6SlhNia",
058 *   "policy_language_crit": ["regexp"],
059 *   "metadata": {
060 *      "openid_provider": {
061 *         "issuer": "https://ntnu.no",
062 *         "organization_name": "NTNU",
063 *      },
064 *      "oauth_client": {
065 *         "organization_name": "NTNU"
066 *      }
067 *   },
068 *   "metadata_policy": {
069 *      "openid_provider": {
070 *         "id_token_signing_alg_values_supported": {
071 *             "subset_of": ["RS256", "RS384", "RS512"]
072 *         },
073 *         "op_policy_uri": {
074 *             "regexp": "^https:\/\/[\\w-]+\\.example\\.com\/[\\w-]+\\.html"}
075 *         },
076 *      "oauth_client": {
077 *         "grant_types": {
078 *         "subset_of": ["authorization_code", "client_credentials"]},
079 *         "scope": {
080 *         "subset_of": ["openid", "profile", "email", "phone"]}
081 *      }
082 *   },
083 *   "constraints": {
084 *      "max_path_length": 2
085 *   },
086 *   "jwks": {
087 *      "keys": [
088 *         {
089 *            "alg": "RS256",
090 *            "e": "AQAB",
091 *            "key_ops": ["verify"],
092 *            "kid": "key1",
093 *            "kty": "RSA",
094 *            "n": "pnXBOusEANuug6ewezb9J_...",
095 *            "use": "sig"
096 *         }
097 *      ]
098 *   }
099 * }
100 * </pre>
101 *
102 * <p>Related specifications:
103 *
104 * <ul>
105 *     <li>OpenID Connect Federation 1.0, section 3.1.
106 * </ul>
107 */
108public class EntityStatementClaimsSet extends CommonFederationClaimsSet {
109        
110        
111        /**
112         * The JWK set claim name.
113         */
114        public static final String JWKS_CLAIM_NAME = "jwks";
115        
116        
117        /**
118         * The authority hints claim name.
119         */
120        public static final String AUTHORITY_HINTS_CLAIM_NAME = "authority_hints";
121        
122        
123        /**
124         * The metadata policy claim name.
125         */
126        public static final String METADATA_POLICY_CLAIM_NAME = "metadata_policy";
127        
128        
129        /**
130         * The assumed trust anchor in a explicit client registration. Intended
131         * for entity statements issued by an OP for RP performing explicit
132         * client registration only.
133         */
134        public static final String TRUST_ANCHOR_ID_CLAIM_NAME = "trust_anchor_id";
135        
136        
137        /**
138         * The constraints claim name.
139         */
140        public static final String CONSTRAINTS_CLAIM_NAME = "constraints";
141        
142        
143        /**
144         * The trust marks issuers claim name.
145         */
146        public static final String TRUST_MARKS_ISSUERS_CLAIM_NAME = "trust_marks_issuers";
147        
148        
149        /**
150         * The critical claim name.
151         */
152        public static final String CRITICAL_CLAIM_NAME = "crit";
153        
154        
155        /**
156         * The policy critical claim name.
157         */
158        public static final String POLICY_LANGUAGE_CRITICAL_CLAIM_NAME = "policy_language_crit";
159        
160        
161        /**
162         * The names of the standard top-level claims.
163         */
164        private static final Set<String> STD_CLAIM_NAMES;
165        
166        static {
167                Set<String> claimNames = new HashSet<>();
168                claimNames.add(ISS_CLAIM_NAME);
169                claimNames.add(SUB_CLAIM_NAME);
170                claimNames.add(IAT_CLAIM_NAME);
171                claimNames.add(EXP_CLAIM_NAME);
172                claimNames.add(JWKS_CLAIM_NAME);
173                claimNames.add(AUD_CLAIM_NAME);
174                claimNames.add(AUTHORITY_HINTS_CLAIM_NAME);
175                claimNames.add(METADATA_CLAIM_NAME);
176                claimNames.add(METADATA_POLICY_CLAIM_NAME);
177                claimNames.add(CONSTRAINTS_CLAIM_NAME);
178                claimNames.add(CRITICAL_CLAIM_NAME);
179                claimNames.add(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME);
180                claimNames.add(TRUST_MARKS_CLAIM_NAME);
181                claimNames.add(TRUST_MARKS_ISSUERS_CLAIM_NAME);
182                claimNames.add(TRUST_ANCHOR_ID_CLAIM_NAME);
183                STD_CLAIM_NAMES = Collections.unmodifiableSet(claimNames);
184        }
185        
186        
187        /**
188         * Gets the names of the standard top-level claims.
189         *
190         * @return The names of the standard top-level claims (read-only set).
191         */
192        public static Set<String> getStandardClaimNames() {
193                
194                return STD_CLAIM_NAMES;
195        }
196        
197        
198        /**
199         * Creates a new federation entity statement claims set with the
200         * minimum required claims.
201         *
202         * @param iss  The issuer. Must not be {@code null}.
203         * @param sub  The subject. Must not be {@code null}.
204         * @param iat  The issue time. Must not be {@code null}.
205         * @param exp  The expiration time. Must not be {@code null}.
206         * @param jwks The entity public JWK set, {@code null} if not required.
207         */
208        public EntityStatementClaimsSet(final Issuer iss,
209                                        final Subject sub,
210                                        final Date iat,
211                                        final Date exp,
212                                        final JWKSet jwks) {
213                
214                this(new EntityID(iss.getValue()), new EntityID(sub.getValue()), iat, exp, jwks);
215        }
216        
217        
218        /**
219         * Creates a new federation entity statement claims set with the
220         * minimum required claims.
221         *
222         * @param iss  The issuer. Must not be {@code null}.
223         * @param sub  The subject. Must not be {@code null}.
224         * @param iat  The issue time. Must not be {@code null}.
225         * @param exp  The expiration time. Must not be {@code null}.
226         * @param jwks The entity public JWK set, {@code null} if not required.
227         */
228        public EntityStatementClaimsSet(final EntityID iss,
229                                        final EntityID sub,
230                                        final Date iat,
231                                        final Date exp,
232                                        final JWKSet jwks) {
233                
234                setClaim(ISS_CLAIM_NAME, iss.getValue());
235                setClaim(SUB_CLAIM_NAME, sub.getValue());
236                
237                if (iat == null) {
238                        throw new IllegalArgumentException("The iat (issued-at) claim must not be null");
239                }
240                setDateClaim(IAT_CLAIM_NAME, iat);
241                
242                if (exp == null) {
243                        throw new IllegalArgumentException("The exp (expiration) claim must not be null");
244                }
245                setDateClaim(EXP_CLAIM_NAME, exp);
246                
247                if (jwks != null) {
248                        setClaim(JWKS_CLAIM_NAME, new JSONObject(jwks.toJSONObject(true))); // public JWKs only
249                }
250        }
251        
252        
253        /**
254         * Creates a new federation entity statement claims set from the
255         * specified JWT claims set.
256         *
257         * @param jwtClaimsSet The JWT claims set. Must not be {@code null}.
258         *
259         * @throws ParseException If the JWT claims set doesn't represent a
260         *                        valid federation entity statement claims set.
261         */
262        public EntityStatementClaimsSet(final JWTClaimsSet jwtClaimsSet)
263                throws ParseException {
264                
265                super(JSONObjectUtils.toJSONObject(jwtClaimsSet));
266                
267                validateRequiredClaimsPresence();
268        }
269        
270        
271        /**
272         * Validates this claims set for having all minimum required claims for
273         * an entity statement. If a {@link #isSelfStatement() selt-statement}
274         * check for the {@link #hasMetadata() presence of metadata}. If
275         * {@link #getCriticalExtensionClaims() critical extension claims} are
276         * listed their presence is also checked.
277         *
278         * @throws ParseException If the validation failed and a required claim
279         *                        is missing.
280         */
281        public void validateRequiredClaimsPresence()
282                throws ParseException {
283                
284                super.validateRequiredClaimsPresence();
285                
286                // jwks always required for self-statements
287                if (isSelfStatement() && getJWKSet() == null) {
288                        throw new ParseException("Missing jwks (JWK set) claim");
289                }
290                
291                if (isSelfStatement() && ! hasMetadata()) {
292                        throw new ParseException("Missing required metadata claim for self-statement");
293                }
294                
295                List<String> crit = getCriticalExtensionClaims();
296                
297                if (crit != null) {
298                        for (String claimName: crit) {
299                                if (getClaim(claimName) == null) {
300                                        throw new ParseException("Missing critical " + claimName + " claim");
301                                }
302                        }
303                }
304        }
305        
306        
307        /**
308         * Returns {@code true} if this is a self-statement (issuer and subject
309         * match).
310         *
311         * @return {@code true} for a self-statement, {@code false} if not.
312         */
313        public boolean isSelfStatement() {
314                
315                Issuer issuer = getIssuer();
316                Subject subject = getSubject();
317                
318                return issuer != null && subject != null && issuer.getValue().equals(subject.getValue());
319        }
320        
321        
322        /**
323         * Gets the entity JWK set. Corresponds to the {@code jwks} claim.
324         *
325         * @return The entity JWK set, {@code null} if not specified or parsing
326         *         failed.
327         */
328        public JWKSet getJWKSet() {
329                
330                JSONObject jwkSetJSONObject = getJSONObjectClaim(JWKS_CLAIM_NAME);
331                if (jwkSetJSONObject == null) {
332                        return null;
333                }
334                try {
335                        return JWKSet.parse(jwkSetJSONObject);
336                } catch (java.text.ParseException e) {
337                        return null;
338                }
339        }
340        
341        
342        /**
343         * Gets the entity IDs of the intermediate entities or trust anchors.
344         * Corresponds to the {@code authority_hints} claim.
345         *
346         * @return The entity IDs, {@code null} or empty list for a trust
347         *         anchor, or if parsing failed.
348         */
349        public List<EntityID> getAuthorityHints() {
350                
351                List<String> strings = getStringListClaim(AUTHORITY_HINTS_CLAIM_NAME);
352                
353                if (strings == null) {
354                        return null;
355                }
356                
357                List<EntityID> trustChain = new LinkedList<>();
358                for (String s: strings) {
359                        trustChain.add(new EntityID(s));
360                }
361                return trustChain;
362        }
363        
364        
365        /**
366         * Sets the entity IDs of the intermediate entities or trust anchors.
367         * Corresponds to the {@code authority_hints} claim.
368         *
369         * @param trustChain The entity IDs, {@code null} or empty list for a
370         *                   trust anchor.
371         */
372        public void setAuthorityHints(final List<EntityID> trustChain) {
373                
374                if (trustChain != null) {
375                        setClaim(AUTHORITY_HINTS_CLAIM_NAME, Identifier.toStringList(trustChain));
376                } else {
377                        setClaim(AUTHORITY_HINTS_CLAIM_NAME, null);
378                }
379        }
380        
381        
382        /**
383         * Returns {@code true} if a metadata field is present. Corresponds to
384         * the {@code metadata} claim.
385         *
386         * @return {@code true} if a metadata field for an OpenID relying
387         *         party, an OpenID provider, an OAuth authorisation server, an
388         *         OAuth client, an OAuth protected resource, a federation
389         *         entity, or a trust mark issuer is present.
390         */
391        public boolean hasMetadata() {
392        
393                JSONObject metadataObject = getJSONObjectClaim(METADATA_CLAIM_NAME);
394                
395                if (MapUtils.isEmpty(metadataObject)) {
396                        return false;
397                }
398                
399                if (metadataObject.get(EntityType.OPENID_RELYING_PARTY.getValue()) != null) return true;
400                if (metadataObject.get(EntityType.OPENID_PROVIDER.getValue()) != null) return true;
401                if (metadataObject.get(EntityType.OAUTH_AUTHORIZATION_SERVER.getValue()) != null) return true;
402                if (metadataObject.get(EntityType.OAUTH_CLIENT.getValue()) != null) return true;
403                if (metadataObject.get(EntityType.OAUTH_RESOURCE.getValue()) != null) return true;
404                if (metadataObject.get(EntityType.FEDERATION_ENTITY.getValue()) != null) return true;
405                if (metadataObject.get(EntityType.TRUST_MARK_ISSUER.getValue()) != null) return true;
406                
407                return false;
408        }
409        
410        
411        /**
412         * Gets the metadata for the specified entity type. Use a typed getter,
413         * such as {@link #getRPMetadata}, when available. Corresponds to the
414         * {@code metadata} claim.
415         *
416         * @param type The entity type. Must not be {@code null}.
417         *
418         * @return The metadata, {@code null} if not specified or if parsing
419         *         failed.
420         */
421        public JSONObject getMetadata(final EntityType type) {
422                
423                JSONObject o = getJSONObjectClaim(METADATA_CLAIM_NAME);
424                
425                if (o == null) {
426                        return null;
427                }
428                
429                try {
430                        return JSONObjectUtils.getJSONObject(o, type.getValue(), null);
431                } catch (ParseException e) {
432                        return null;
433                }
434        }
435        
436        
437        /**
438         * Sets the metadata for the specified entity type. Use a typed setter,
439         * such as {@link #setRPMetadata}, when available. Corresponds to the
440         * {@code metadata} claim.
441         *
442         * @param type     The type. Must not be {@code null}.
443         * @param metadata The metadata, {@code null} if not specified.
444         */
445        public void setMetadata(final EntityType type, final JSONObject metadata) {
446                
447                JSONObject o = getJSONObjectClaim(METADATA_CLAIM_NAME);
448                
449                if (o == null) {
450                        if (metadata == null) {
451                                return; // nothing to clear
452                        }
453                        o = new JSONObject();
454                }
455                
456                o.put(type.getValue(), metadata);
457                
458                setClaim(METADATA_CLAIM_NAME, o);
459        }
460        
461        
462        /**
463         * Sets the OpenID relying party metadata if present for this entity.
464         * Corresponds to the {@code metadata.openid_relying_party} claim.
465         *
466         * @param rpMetadata The RP metadata, {@code null} if not specified.
467         */
468        public void setRPMetadata(final OIDCClientMetadata rpMetadata) {
469                
470                JSONObject o = rpMetadata != null ? rpMetadata.toJSONObject() : null;
471                setMetadata(EntityType.OPENID_RELYING_PARTY, o);
472        }
473        
474        
475        /**
476         * Gets the OpenID provider metadata if present for this entity.
477         * Corresponds to the {@code metadata.openid_provider} claim.
478         *
479         * @param opMetadata The OP metadata, {@code null} if not specified.
480         */
481        public void setOPMetadata(final OIDCProviderMetadata opMetadata) {
482                
483                JSONObject o = opMetadata != null ? opMetadata.toJSONObject() : null;
484                setMetadata(EntityType.OPENID_PROVIDER, o);
485        }
486        
487        
488        /**
489         * Sets the OAuth 2.0 client metadata if present for this entity.
490         * Corresponds to the {@code metadata.oauth_client} claim.
491         *
492         * @param clientMetadata The client metadata, {@code null} if not
493         *                       specified.
494         */
495        public void setOAuthClientMetadata(final ClientMetadata clientMetadata) {
496                
497                JSONObject o = clientMetadata != null ? clientMetadata.toJSONObject() : null;
498                setMetadata(EntityType.OAUTH_CLIENT, o);
499        }
500        
501        
502        /**
503         * Sets the OAuth 2.0 authorisation server metadata if present for this
504         * entity. Corresponds to the
505         * {@code metadata.oauth_authorization_server} claim.
506         *
507         * @param asMetadata The AS metadata, {@code null} if not specified.
508         */
509        public void setASMetadata(final AuthorizationServerMetadata asMetadata) {
510                
511                JSONObject o = asMetadata != null ? asMetadata.toJSONObject() : null;
512                setMetadata(EntityType.OAUTH_AUTHORIZATION_SERVER, o);
513        }
514        
515        
516        /**
517         * Sets the federation entity metadata if present for this entity.
518         * Corresponds to the {@code metadata.federation_entity} claim.
519         *
520         * @param entityMetadata The federation entity metadata, {@code null}
521         *                       if not specified.
522         */
523        public void setFederationEntityMetadata(final FederationEntityMetadata entityMetadata) {
524                
525                JSONObject o = entityMetadata != null ? entityMetadata.toJSONObject() : null;
526                setMetadata(EntityType.FEDERATION_ENTITY, o);
527        }
528        
529        
530        /**
531         * Sets the trust mark issuer metadata for this entity.
532         * Corresponds to the {@code metadata.trust_mark_issuer} claim.
533         *
534         * @param trustMarkIssuerMetadata The trust mark issuer metadata,
535         *                                {@code null} if not specified.
536         */
537        public void setTrustMarkIssuerMetadata(final TrustMarkIssuerMetadata trustMarkIssuerMetadata) {
538                
539                JSONObject o = trustMarkIssuerMetadata != null ? trustMarkIssuerMetadata.toJSONObject() : null;
540                setMetadata(EntityType.TRUST_MARK_ISSUER, o);
541        }
542        
543        
544        /**
545         * Gets the complete metadata policy JSON object. Corresponds to the
546         * {@code metadata_policy} claim.
547         *
548         * @return The metadata policy JSON object, {@code null} if not
549         *         specified or if parsing failed.
550         */
551        public JSONObject getMetadataPolicyJSONObject() {
552                
553                return getJSONObjectClaim(METADATA_POLICY_CLAIM_NAME);
554        }
555        
556        
557        /**
558         * Sets the complete metadata policy JSON object. Corresponds to the
559         * {@code metadata_policy} claim.
560         *
561         * @param metadataPolicy The metadata policy JSON object, {@code null}
562         *                       if not specified.
563         */
564        public void setMetadataPolicyJSONObject(final JSONObject metadataPolicy) {
565        
566                setClaim(METADATA_POLICY_CLAIM_NAME, metadataPolicy);
567        }
568        
569        
570        /**
571         * Gets the metadata policy for the specified type. Corresponds to the
572         * {@code metadata_policy} claim.
573         *
574         * @param type The entity type. Must not be {@code null}.
575         *
576         * @return The metadata policy, {@code null} or if JSON parsing failed.
577         *
578         * @throws PolicyViolationException On a policy violation.
579         */
580        public MetadataPolicy getMetadataPolicy(final EntityType type)
581                throws PolicyViolationException {
582                
583                JSONObject o = getMetadataPolicyJSONObject();
584                
585                if (o == null) {
586                        return null;
587                }
588                
589                try {
590                        JSONObject policyJSONObject = JSONObjectUtils.getJSONObject(o, type.getValue(), null);
591                        if (policyJSONObject == null) {
592                                return null;
593                        }
594                        return MetadataPolicy.parse(policyJSONObject);
595                } catch (ParseException e) {
596                        return null;
597                }
598        }
599        
600        
601        /**
602         * Sets the metadata policy for the specified type. Corresponds to the
603         * {@code metadata_policy} claim.
604         *
605         * @param type           The entity type. Must not be {@code null}.
606         * @param metadataPolicy The metadata policy, {@code null} if not
607         *                       specified.
608         */
609        public void setMetadataPolicy(final EntityType type, final MetadataPolicy metadataPolicy) {
610                
611                JSONObject o = getMetadataPolicyJSONObject();
612                
613                if (o == null) {
614                        if (metadataPolicy == null) {
615                                return; // nothing to clear
616                        }
617                        o = new JSONObject();
618                }
619                
620                if (metadataPolicy != null) {
621                        o.put(type.getValue(), metadataPolicy.toJSONObject());
622                } else {
623                        o.remove(type.getValue());
624                }
625                
626                if (o.isEmpty()) {
627                        o = null;
628                }
629                setMetadataPolicyJSONObject(o);
630        }
631        
632        
633        /**
634         * Gets the used trust anchor in a explicit client registration in
635         * OpenID Connect Federation 1.0. Intended for entity statements issued
636         * by an OpenID provider for a Relying party performing explicit client
637         * registration only. Corresponds to the {@code trust_anchor_id} claim.
638         *
639         * @return The trust anchor ID, {@code null} if not specified.
640         */
641        public EntityID getTrustAnchorID() {
642                
643                String value = getStringClaim(TRUST_ANCHOR_ID_CLAIM_NAME);
644                
645                try {
646                        return EntityID.parse(value);
647                } catch (ParseException e) {
648                        return null;
649                }
650        }
651        
652        
653        /**
654         * Sets the used trust anchor in a explicit client registration in
655         * OpenID Connect Federation 1.0. Intended for entity statements issued
656         * by an OpenID provider for a Relying party performing explicit client
657         * registration only. Corresponds to the {@code trust_anchor_id} claim.
658         *
659         * @param trustAnchorID The trust anchor ID, {@code null} if not
660         *                      specified.
661         */
662        public void setTrustAnchorID(final EntityID trustAnchorID) {
663                
664                if (trustAnchorID != null) {
665                        setClaim(TRUST_ANCHOR_ID_CLAIM_NAME, trustAnchorID.getValue());
666                } else {
667                        setClaim(TRUST_ANCHOR_ID_CLAIM_NAME, null);
668                }
669        }
670        
671        
672        /**
673         * Gets the trust chain constraints for subordinate entities.
674         * Corresponds to the {@code constraints} claim.
675         *
676         * @return The trust chain constraints, {@code null} if not specified
677         *          or if parsing failed.
678         */
679        public TrustChainConstraints getConstraints() {
680                
681                JSONObject o = getJSONObjectClaim(CONSTRAINTS_CLAIM_NAME);
682                
683                if (o == null) {
684                        return null;
685                }
686                
687                try {
688                        return TrustChainConstraints.parse(o);
689                } catch (ParseException e) {
690                        return null;
691                }
692        }
693        
694        
695        /**
696         * Sets the trust chain constraint for subordinate entities.
697         * Corresponds to the {@code constraints} claim.
698         *
699         * @param constraints The trust chain constraints, {@code null} if not
700         *                    specified.
701         */
702        public void setConstraints(final TrustChainConstraints constraints) {
703        
704                if (constraints != null) {
705                        setClaim(CONSTRAINTS_CLAIM_NAME, constraints.toJSONObject());
706                } else {
707                        setClaim(CONSTRAINTS_CLAIM_NAME, null);
708                }
709        }
710        
711        
712        /**
713         * Sets the trust marks. Corresponds to the {@code trust_marks} claim.
714         *
715         * @param marks The trust marks, {@code null} if not specified.
716         */
717        public void setTrustMarks(final List<TrustMarkEntry> marks) {
718                
719                if (marks != null) {
720                        JSONArray array = new JSONArray();
721                        for (TrustMarkEntry en: marks) {
722                                array.add(en.toJSONObject());
723                        }
724                        setClaim(TRUST_MARKS_CLAIM_NAME, array);
725                } else {
726                        setClaim(TRUST_MARKS_CLAIM_NAME, null);
727                }
728        }
729        
730        
731        /**
732         * Gets the trust marks issuers. Corresponds to the
733         * {@code trust_marks_issuers} claim.
734         *
735         * @return The trust marks issuers, {@code null} if not specified or
736         *         parsing failed.
737         */
738        public Map<Identifier, List<Issuer>> getTrustMarksIssuers() {
739                
740                JSONObject o = getJSONObjectClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME);
741                
742                if (o == null) {
743                        return null;
744                }
745                
746                Map<Identifier, List<Issuer>> issuers = new HashMap<>();
747                
748                for (String id: o.keySet()) {
749                        try {
750                                List<Issuer> issuerList = new LinkedList<>();
751                                for (String issuerString: JSONObjectUtils.getStringList(o, id)) {
752                                        issuerList.add(new Issuer(issuerString));
753                                }
754                                issuers.put(new Identifier(id), issuerList);
755                        } catch (ParseException e) {
756                                return null;
757                        }
758                }
759                
760                return issuers;
761        }
762        
763        
764        /**
765         * Sets the trust marks issuers. Corresponds to the
766         * {@code trust_marks_issuers} claim.
767         *
768         * @param issuers The trust marks issuers, {@code null} if not
769         *                specified.
770         */
771        public void setTrustMarksIssuers(final Map<Identifier, List<Issuer>> issuers) {
772                
773                if (issuers != null) {
774                        JSONObject issuersObject = new JSONObject();
775                        for (Map.Entry<Identifier, List<Issuer>> en: issuers.entrySet()) {
776                                issuersObject.put(en.getKey().getValue(), Issuer.toStringList(en.getValue()));
777                                setClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME, issuersObject);
778                        }
779                } else {
780                        setClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME, null);
781                }
782        }
783        
784        
785        /**
786         * Gets the names of the critical extension claims. Corresponds to the
787         * {@code crit} claim.
788         *
789         * @return The names of the critical extension claims, {@code null} if
790         *         not specified or if parsing failed.
791         */
792        public List<String> getCriticalExtensionClaims() {
793                
794                return getStringListClaim(CRITICAL_CLAIM_NAME);
795        }
796        
797        
798        /**
799         * Sets the names of the critical extension claims. Corresponds to the
800         * {@code crit} claim.
801         *
802         * @param claimNames The names of the critical extension claims,
803         *                   {@code null} if not specified. Must not be an
804         *                   empty list.
805         */
806        public void setCriticalExtensionClaims(final List<String> claimNames) {
807        
808                if (claimNames != null && claimNames.isEmpty()) {
809                        throw new IllegalArgumentException("The critical extension claim names must not be empty");
810                }
811                
812                setClaim(CRITICAL_CLAIM_NAME, claimNames);
813        }
814        
815        
816        /**
817         * Gets the names of the critical policy extensions. Corresponds to the
818         * {@code policy_language_crit} claim.
819         *
820         * @return The names of the critical policy extensions or if parsing
821         *         failed.
822         */
823        public List<String> getCriticalPolicyExtensions() {
824                
825                return getStringListClaim(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME);
826        }
827        
828        
829        /**
830         * Sets the names of the critical policy extensions. Corresponds to the
831         * {@code policy_language_crit} claim.
832         *
833         * @param extNames The names of the critical policy extensions,
834         *                 {@code null} if not specified. Must not be an empty
835         *                 list.
836         */
837        public void setCriticalPolicyExtensions(final List<String> extNames) {
838        
839                if (extNames != null && extNames.isEmpty()) {
840                        throw new IllegalArgumentException("The critical policy extension names must not be empty");
841                }
842                
843                setClaim(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME, extNames);
844        }
845}