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        @Deprecated
538        public void setTrustMarkIssuerMetadata(final TrustMarkIssuerMetadata trustMarkIssuerMetadata) {
539                
540                JSONObject o = trustMarkIssuerMetadata != null ? trustMarkIssuerMetadata.toJSONObject() : null;
541                setMetadata(EntityType.TRUST_MARK_ISSUER, o);
542        }
543        
544        
545        /**
546         * Gets the complete metadata policy JSON object. Corresponds to the
547         * {@code metadata_policy} claim.
548         *
549         * @return The metadata policy JSON object, {@code null} if not
550         *         specified or if parsing failed.
551         */
552        public JSONObject getMetadataPolicyJSONObject() {
553                
554                return getJSONObjectClaim(METADATA_POLICY_CLAIM_NAME);
555        }
556        
557        
558        /**
559         * Sets the complete metadata policy JSON object. Corresponds to the
560         * {@code metadata_policy} claim.
561         *
562         * @param metadataPolicy The metadata policy JSON object, {@code null}
563         *                       if not specified.
564         */
565        public void setMetadataPolicyJSONObject(final JSONObject metadataPolicy) {
566        
567                setClaim(METADATA_POLICY_CLAIM_NAME, metadataPolicy);
568        }
569        
570        
571        /**
572         * Gets the metadata policy for the specified type. Corresponds to the
573         * {@code metadata_policy} claim.
574         *
575         * @param type The entity type. Must not be {@code null}.
576         *
577         * @return The metadata policy, {@code null} or if JSON parsing failed.
578         *
579         * @throws PolicyViolationException On a policy violation.
580         */
581        public MetadataPolicy getMetadataPolicy(final EntityType type)
582                throws PolicyViolationException {
583                
584                JSONObject o = getMetadataPolicyJSONObject();
585                
586                if (o == null) {
587                        return null;
588                }
589                
590                try {
591                        JSONObject policyJSONObject = JSONObjectUtils.getJSONObject(o, type.getValue(), null);
592                        if (policyJSONObject == null) {
593                                return null;
594                        }
595                        return MetadataPolicy.parse(policyJSONObject);
596                } catch (ParseException e) {
597                        return null;
598                }
599        }
600        
601        
602        /**
603         * Sets the metadata policy for the specified type. Corresponds to the
604         * {@code metadata_policy} claim.
605         *
606         * @param type           The entity type. Must not be {@code null}.
607         * @param metadataPolicy The metadata policy, {@code null} if not
608         *                       specified.
609         */
610        public void setMetadataPolicy(final EntityType type, final MetadataPolicy metadataPolicy) {
611                
612                JSONObject o = getMetadataPolicyJSONObject();
613                
614                if (o == null) {
615                        if (metadataPolicy == null) {
616                                return; // nothing to clear
617                        }
618                        o = new JSONObject();
619                }
620                
621                if (metadataPolicy != null) {
622                        o.put(type.getValue(), metadataPolicy.toJSONObject());
623                } else {
624                        o.remove(type.getValue());
625                }
626                
627                if (o.isEmpty()) {
628                        o = null;
629                }
630                setMetadataPolicyJSONObject(o);
631        }
632        
633        
634        /**
635         * Gets the used trust anchor in a explicit client registration in
636         * OpenID Connect Federation 1.0. Intended for entity statements issued
637         * by an OpenID provider for a Relying party performing explicit client
638         * registration only. Corresponds to the {@code trust_anchor_id} claim.
639         *
640         * @return The trust anchor ID, {@code null} if not specified.
641         */
642        public EntityID getTrustAnchorID() {
643                
644                String value = getStringClaim(TRUST_ANCHOR_ID_CLAIM_NAME);
645                
646                try {
647                        return EntityID.parse(value);
648                } catch (ParseException e) {
649                        return null;
650                }
651        }
652        
653        
654        /**
655         * Sets the used trust anchor in a explicit client registration in
656         * OpenID Connect Federation 1.0. Intended for entity statements issued
657         * by an OpenID provider for a Relying party performing explicit client
658         * registration only. Corresponds to the {@code trust_anchor_id} claim.
659         *
660         * @param trustAnchorID The trust anchor ID, {@code null} if not
661         *                      specified.
662         */
663        public void setTrustAnchorID(final EntityID trustAnchorID) {
664                
665                if (trustAnchorID != null) {
666                        setClaim(TRUST_ANCHOR_ID_CLAIM_NAME, trustAnchorID.getValue());
667                } else {
668                        setClaim(TRUST_ANCHOR_ID_CLAIM_NAME, null);
669                }
670        }
671        
672        
673        /**
674         * Gets the trust chain constraints for subordinate entities.
675         * Corresponds to the {@code constraints} claim.
676         *
677         * @return The trust chain constraints, {@code null} if not specified
678         *          or if parsing failed.
679         */
680        public TrustChainConstraints getConstraints() {
681                
682                JSONObject o = getJSONObjectClaim(CONSTRAINTS_CLAIM_NAME);
683                
684                if (o == null) {
685                        return null;
686                }
687                
688                try {
689                        return TrustChainConstraints.parse(o);
690                } catch (ParseException e) {
691                        return null;
692                }
693        }
694        
695        
696        /**
697         * Sets the trust chain constraint for subordinate entities.
698         * Corresponds to the {@code constraints} claim.
699         *
700         * @param constraints The trust chain constraints, {@code null} if not
701         *                    specified.
702         */
703        public void setConstraints(final TrustChainConstraints constraints) {
704        
705                if (constraints != null) {
706                        setClaim(CONSTRAINTS_CLAIM_NAME, constraints.toJSONObject());
707                } else {
708                        setClaim(CONSTRAINTS_CLAIM_NAME, null);
709                }
710        }
711        
712        
713        /**
714         * Sets the trust marks. Corresponds to the {@code trust_marks} claim.
715         *
716         * @param marks The trust marks, {@code null} if not specified.
717         */
718        public void setTrustMarks(final List<TrustMarkEntry> marks) {
719                
720                if (marks != null) {
721                        JSONArray array = new JSONArray();
722                        for (TrustMarkEntry en: marks) {
723                                array.add(en.toJSONObject());
724                        }
725                        setClaim(TRUST_MARKS_CLAIM_NAME, array);
726                } else {
727                        setClaim(TRUST_MARKS_CLAIM_NAME, null);
728                }
729        }
730        
731        
732        /**
733         * Gets the trust marks issuers. Corresponds to the
734         * {@code trust_marks_issuers} claim.
735         *
736         * @return The trust marks issuers, {@code null} if not specified or
737         *         parsing failed.
738         */
739        public Map<Identifier, List<Issuer>> getTrustMarksIssuers() {
740                
741                JSONObject o = getJSONObjectClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME);
742                
743                if (o == null) {
744                        return null;
745                }
746                
747                Map<Identifier, List<Issuer>> issuers = new HashMap<>();
748                
749                for (String id: o.keySet()) {
750                        try {
751                                List<Issuer> issuerList = new LinkedList<>();
752                                for (String issuerString: JSONObjectUtils.getStringList(o, id)) {
753                                        issuerList.add(new Issuer(issuerString));
754                                }
755                                issuers.put(new Identifier(id), issuerList);
756                        } catch (ParseException e) {
757                                return null;
758                        }
759                }
760                
761                return issuers;
762        }
763        
764        
765        /**
766         * Sets the trust marks issuers. Corresponds to the
767         * {@code trust_marks_issuers} claim.
768         *
769         * @param issuers The trust marks issuers, {@code null} if not
770         *                specified.
771         */
772        public void setTrustMarksIssuers(final Map<Identifier, List<Issuer>> issuers) {
773                
774                if (issuers != null) {
775                        JSONObject issuersObject = new JSONObject();
776                        for (Map.Entry<Identifier, List<Issuer>> en: issuers.entrySet()) {
777                                issuersObject.put(en.getKey().getValue(), Issuer.toStringList(en.getValue()));
778                                setClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME, issuersObject);
779                        }
780                } else {
781                        setClaim(TRUST_MARKS_ISSUERS_CLAIM_NAME, null);
782                }
783        }
784        
785        
786        /**
787         * Gets the names of the critical extension claims. Corresponds to the
788         * {@code crit} claim.
789         *
790         * @return The names of the critical extension claims, {@code null} if
791         *         not specified or if parsing failed.
792         */
793        public List<String> getCriticalExtensionClaims() {
794                
795                return getStringListClaim(CRITICAL_CLAIM_NAME);
796        }
797        
798        
799        /**
800         * Sets the names of the critical extension claims. Corresponds to the
801         * {@code crit} claim.
802         *
803         * @param claimNames The names of the critical extension claims,
804         *                   {@code null} if not specified. Must not be an
805         *                   empty list.
806         */
807        public void setCriticalExtensionClaims(final List<String> claimNames) {
808        
809                if (claimNames != null && claimNames.isEmpty()) {
810                        throw new IllegalArgumentException("The critical extension claim names must not be empty");
811                }
812                
813                setClaim(CRITICAL_CLAIM_NAME, claimNames);
814        }
815        
816        
817        /**
818         * Gets the names of the critical policy extensions. Corresponds to the
819         * {@code policy_language_crit} claim.
820         *
821         * @return The names of the critical policy extensions or if parsing
822         *         failed.
823         */
824        public List<String> getCriticalPolicyExtensions() {
825                
826                return getStringListClaim(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME);
827        }
828        
829        
830        /**
831         * Sets the names of the critical policy extensions. Corresponds to the
832         * {@code policy_language_crit} claim.
833         *
834         * @param extNames The names of the critical policy extensions,
835         *                 {@code null} if not specified. Must not be an empty
836         *                 list.
837         */
838        public void setCriticalPolicyExtensions(final List<String> extNames) {
839        
840                if (extNames != null && extNames.isEmpty()) {
841                        throw new IllegalArgumentException("The critical policy extension names must not be empty");
842                }
843                
844                setClaim(POLICY_LANGUAGE_CRITICAL_CLAIM_NAME, extNames);
845        }
846}