001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2016, Connect2id Ltd.
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.jose;
019
020
021import java.net.URI;
022import java.text.ParseException;
023import java.util.*;
024
025import net.jcip.annotations.Immutable;
026
027import com.nimbusds.jose.jwk.JWK;
028import com.nimbusds.jose.util.Base64;
029import com.nimbusds.jose.util.Base64URL;
030import com.nimbusds.jose.util.JSONObjectUtils;
031import com.nimbusds.jose.util.X509CertChainUtils;
032
033
034/**
035 * JSON Web Encryption (JWE) header. This class is immutable.
036 *
037 * <p>Supports all {@link #getRegisteredParameterNames registered header
038 * parameters} of the JWE specification:
039 *
040 * <ul>
041 *     <li>alg
042 *     <li>enc
043 *     <li>epk
044 *     <li>zip
045 *     <li>jku
046 *     <li>jwk
047 *     <li>x5u
048 *     <li>x5t
049 *     <li>x5t#S256
050 *     <li>x5c
051 *     <li>kid
052 *     <li>typ
053 *     <li>cty
054 *     <li>crit
055 *     <li>apu
056 *     <li>apv
057 *     <li>p2s
058 *     <li>p2c
059 *     <li>iv
060 *     <li>authTag
061 * </ul>
062 *
063 * <p>The header may also include {@link #getCustomParams custom
064 * parameters}; these will be serialised and parsed along the registered ones.
065 *
066 * <p>Example header:
067 *
068 * <pre>
069 * { 
070 *   "alg" : "RSA1_5",
071 *   "enc" : "A128CBC-HS256"
072 * }
073 * </pre>
074 *
075 * @author Vladimir Dzhuvinov
076 * @version 2021-06-05
077 */
078@Immutable
079public final class JWEHeader extends CommonSEHeader {
080
081
082        private static final long serialVersionUID = 1L;
083
084
085        /**
086         * The registered parameter names.
087         */
088        private static final Set<String> REGISTERED_PARAMETER_NAMES;
089
090
091        /*
092         * Initialises the registered parameter name set.
093         */
094        static {
095                Set<String> p = new HashSet<>();
096
097                p.add(HeaderParameterNames.ALGORITHM);
098                p.add(HeaderParameterNames.ENCRYPTION_ALGORITHM);
099                p.add(HeaderParameterNames.EPHEMERAL_PUBLIC_KEY);
100                p.add(HeaderParameterNames.COMPRESSION_ALGORITHM);
101                p.add(HeaderParameterNames.JWK_SET_URL);
102                p.add(HeaderParameterNames.JWK);
103                p.add(HeaderParameterNames.X_509_CERT_URL);
104                p.add(HeaderParameterNames.X_509_CERT_SHA_1_THUMBPRINT);
105                p.add(HeaderParameterNames.X_509_CERT_SHA_256_THUMBPRINT);
106                p.add(HeaderParameterNames.X_509_CERT_CHAIN);
107                p.add(HeaderParameterNames.KEY_ID);
108                p.add(HeaderParameterNames.TYPE);
109                p.add(HeaderParameterNames.CONTENT_TYPE);
110                p.add(HeaderParameterNames.CRITICAL);
111                p.add(HeaderParameterNames.AGREEMENT_PARTY_U_INFO);
112                p.add(HeaderParameterNames.AGREEMENT_PARTY_V_INFO);
113                p.add(HeaderParameterNames.PBES2_SALT_INPUT);
114                p.add(HeaderParameterNames.PBES2_COUNT);
115                p.add(HeaderParameterNames.INITIALIZATION_VECTOR);
116                p.add(HeaderParameterNames.AUTHENTICATION_TAG);
117                p.add("authTag"); // this is a non-standard header, but we should leave it for backwards compatibility
118
119                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
120        }
121
122
123        /**
124         * Builder for constructing JSON Web Encryption (JWE) headers.
125         *
126         * <p>Example usage:
127         *
128         * <pre>
129         * JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.RSA1_5, EncryptionMethod.A128GCM).
130         *                    contentType("text/plain").
131         *                    customParam("exp", new Date().getTime()).
132         *                    build();
133         * </pre>
134         */
135        public static class Builder {
136
137
138                /**
139                 * The JWE algorithm.
140                 */
141                private final JWEAlgorithm alg;
142
143
144                /**
145                 * The encryption method.
146                 */
147                private final EncryptionMethod enc;
148
149
150                /**
151                 * The JOSE object type.
152                 */
153                private JOSEObjectType typ;
154
155
156                /**
157                 * The content type.
158                 */
159                private String cty;
160
161
162                /**
163                 * The critical headers.
164                 */
165                private Set<String> crit;
166
167
168                /**
169                 * JWK Set URL.
170                 */
171                private URI jku;
172
173
174                /**
175                 * JWK.
176                 */
177                private JWK jwk;
178
179
180                /**
181                 * X.509 certificate URL.
182                 */
183                private URI x5u;
184
185
186                /**
187                 * X.509 certificate SHA-1 thumbprint.
188                 */
189                @Deprecated
190                private Base64URL x5t;
191
192
193                /**
194                 * X.509 certificate SHA-256 thumbprint.
195                 */
196                private Base64URL x5t256;
197
198
199                /**
200                 * The X.509 certificate chain corresponding to the key used to
201                 * sign the JWS object.
202                 */
203                private List<Base64> x5c;
204
205
206                /**
207                 * Key ID.
208                 */
209                private String kid;
210
211
212                /**
213                 * The ephemeral public key.
214                 */
215                private JWK epk;
216
217
218                /**
219                 * The compression algorithm.
220                 */
221                private CompressionAlgorithm zip;
222
223
224                /**
225                 * The agreement PartyUInfo.
226                 */
227                private Base64URL apu;
228
229
230                /**
231                 * The agreement PartyVInfo.
232                 */
233                private Base64URL apv;
234
235
236                /**
237                 * The PBES2 salt.
238                 */
239                private Base64URL p2s;
240
241
242                /**
243                 * The PBES2 count.
244                 */
245                private int p2c;
246
247
248                /**
249                 * The initialisation vector.
250                 */
251                private Base64URL iv;
252
253
254                /**
255                 * The authentication authTag.
256                 */
257                private Base64URL tag;
258
259
260                /**
261                 * Custom header parameters.
262                 */
263                private Map<String,Object> customParams;
264
265
266                /**
267                 * The parsed Base64URL.
268                 */
269                private Base64URL parsedBase64URL;
270
271
272                /**
273                 * Creates a new JWE header builder.
274                 *
275                 * @param alg The JWE algorithm ({@code alg}) parameter. Must
276                 *            not be "none" or {@code null}.
277                 * @param enc The encryption method. Must not be {@code null}.
278                 */
279                public Builder(final JWEAlgorithm alg, final EncryptionMethod enc) {
280
281                        if (alg.getName().equals(Algorithm.NONE.getName())) {
282                                throw new IllegalArgumentException("The JWE algorithm \"alg\" cannot be \"none\"");
283                        }
284
285                        this.alg = alg;
286
287                        if (enc == null) {
288                                throw new IllegalArgumentException("The encryption method \"enc\" parameter must not be null");
289                        }
290
291                        this.enc = enc;
292                }
293
294
295                /**
296                 * Creates a new JWE header builder with the parameters from
297                 * the specified header.
298                 *
299                 * @param jweHeader The JWE header to use. Must not not be 
300                 *                  {@code null}.              
301                 */
302                public Builder(final JWEHeader jweHeader) {
303
304                        this(jweHeader.getAlgorithm(), jweHeader.getEncryptionMethod());
305
306                        typ = jweHeader.getType();
307                        cty = jweHeader.getContentType();
308                        crit = jweHeader.getCriticalParams();
309                        customParams = jweHeader.getCustomParams();
310
311                        jku = jweHeader.getJWKURL();
312                        jwk = jweHeader.getJWK();
313                        x5u = jweHeader.getX509CertURL();
314                        x5t = jweHeader.getX509CertThumbprint();
315                        x5t256 = jweHeader.getX509CertSHA256Thumbprint();
316                        x5c = jweHeader.getX509CertChain();
317                        kid = jweHeader.getKeyID();
318
319                        epk = jweHeader.getEphemeralPublicKey();
320                        zip = jweHeader.getCompressionAlgorithm();
321                        apu = jweHeader.getAgreementPartyUInfo();
322                        apv = jweHeader.getAgreementPartyVInfo();
323                        p2s = jweHeader.getPBES2Salt();
324                        p2c = jweHeader.getPBES2Count();
325                        iv = jweHeader.getIV();
326                        tag = jweHeader.getAuthTag();
327
328                        customParams = jweHeader.getCustomParams();
329                }
330
331
332                /**
333                 * Sets the type ({@code typ}) parameter.
334                 *
335                 * @param typ The type parameter, {@code null} if not
336                 *            specified.
337                 *
338                 * @return This builder.
339                 */
340                public Builder type(final JOSEObjectType typ) {
341
342                        this.typ = typ;
343                        return this;
344                }
345
346
347                /**
348                 * Sets the content type ({@code cty}) parameter.
349                 *
350                 * @param cty The content type parameter, {@code null} if not
351                 *            specified.
352                 *
353                 * @return This builder.
354                 */
355                public Builder contentType(final String cty) {
356
357                        this.cty = cty;
358                        return this;
359                }
360
361
362                /**
363                 * Sets the critical header parameters ({@code crit})
364                 * parameter.
365                 *
366                 * @param crit The names of the critical header parameters,
367                 *             empty set or {@code null} if none.
368                 *
369                 * @return This builder.
370                 */
371                public Builder criticalParams(final Set<String> crit) {
372
373                        this.crit = crit;
374                        return this;
375                }
376
377
378                /**
379                 * Sets the JSON Web Key (JWK) Set URL ({@code jku}) parameter.
380                 *
381                 * @param jku The JSON Web Key (JWK) Set URL parameter,
382                 *            {@code null} if not specified.
383                 *
384                 * @return This builder.
385                 */
386                public Builder jwkURL(final URI jku) {
387
388                        this.jku = jku;
389                        return this;
390                }
391
392
393                /**
394                 * Sets the JSON Web Key (JWK) ({@code jwk}) parameter.
395                 *
396                 * @param jwk The JSON Web Key (JWK) ({@code jwk}) parameter,
397                 *            {@code null} if not specified.
398                 *
399                 * @return This builder.
400                 */
401                public Builder jwk(final JWK jwk) {
402
403                        this.jwk = jwk;
404                        return this;
405                }
406
407
408                /**
409                 * Sets the X.509 certificate URL ({@code x5u}) parameter.
410                 *
411                 * @param x5u The X.509 certificate URL parameter, {@code null}
412                 *            if not specified.
413                 *
414                 * @return This builder.
415                 */
416                public Builder x509CertURL(final URI x5u) {
417
418                        this.x5u = x5u;
419                        return this;
420                }
421
422
423                /**
424                 * Sets the X.509 certificate SHA-1 thumbprint ({@code x5t})
425                 * parameter.
426                 *
427                 * @param x5t The X.509 certificate SHA-1 thumbprint parameter,
428                 *            {@code null} if not specified.
429                 *
430                 * @return This builder.
431                 */
432                @Deprecated
433                public Builder x509CertThumbprint(final Base64URL x5t) {
434
435                        this.x5t = x5t;
436                        return this;
437                }
438
439
440                /**
441                 * Sets the X.509 certificate SHA-256 thumbprint
442                 * ({@code x5t#s256}) parameter.
443                 *
444                 * @param x5t256 The X.509 certificate SHA-256 thumbprint
445                 *               parameter, {@code null} if not specified.
446                 *
447                 * @return This builder.
448                 */
449                public Builder x509CertSHA256Thumbprint(final Base64URL x5t256) {
450
451                        this.x5t256 = x5t256;
452                        return this;
453                }
454
455
456                /**
457                 * Sets the X.509 certificate chain parameter ({@code x5c})
458                 * corresponding to the key used to sign the JWS object.
459                 *
460                 * @param x5c The X.509 certificate chain parameter,
461                 *            {@code null} if not specified.
462                 *
463                 * @return This builder.
464                 */
465                public Builder x509CertChain(final List<Base64> x5c) {
466
467                        this.x5c = x5c;
468                        return this;
469                }
470
471
472                /**
473                 * Sets the key ID ({@code kid}) parameter.
474                 *
475                 * @param kid The key ID parameter, {@code null} if not
476                 *            specified.
477                 *
478                 * @return This builder.
479                 */
480                public Builder keyID(final String kid) {
481
482                        this.kid = kid;
483                        return this;
484                }
485
486
487                /**
488                 * Sets the Ephemeral Public Key ({@code epk}) parameter.
489                 *
490                 * @param epk The Ephemeral Public Key parameter, {@code null}
491                 *            if not specified.
492                 *
493                 * @return This builder.
494                 */
495                public Builder ephemeralPublicKey(final JWK epk) {
496
497                        this.epk = epk;
498                        return this;
499                }
500
501
502                /**
503                 * Sets the compression algorithm ({@code zip}) parameter.
504                 *
505                 * @param zip The compression algorithm parameter, {@code null}
506                 *            if not specified.
507                 *
508                 * @return This builder.
509                 */
510                public Builder compressionAlgorithm(final CompressionAlgorithm zip) {
511
512                        this.zip = zip;
513                        return this;
514                }
515
516
517                /**
518                 * Sets the agreement PartyUInfo ({@code apu}) parameter.
519                 *
520                 * @param apu The agreement PartyUInfo parameter, {@code null}
521                 *            if not specified.
522                 *
523                 * @return This builder.
524                 */
525                public Builder agreementPartyUInfo(final Base64URL apu) {
526
527                        this.apu = apu;
528                        return this;
529                }
530
531
532                /**
533                 * Sets the agreement PartyVInfo ({@code apv}) parameter.
534                 *
535                 * @param apv The agreement PartyVInfo parameter, {@code null}
536                 *            if not specified.
537                 *
538                 * @return This builder.
539                 */
540                public Builder agreementPartyVInfo(final Base64URL apv) {
541
542                        this.apv = apv;
543                        return this;
544                }
545
546
547                /**
548                 * Sets the PBES2 salt ({@code p2s}) parameter.
549                 *
550                 * @param p2s The PBES2 salt parameter, {@code null} if not
551                 *            specified.
552                 *
553                 * @return This builder.
554                 */
555                public Builder pbes2Salt(final Base64URL p2s) {
556
557                        this.p2s = p2s;
558                        return this;
559                }
560
561
562                /**
563                 * Sets the PBES2 count ({@code p2c}) parameter.
564                 *
565                 * @param p2c The PBES2 count parameter, zero if not specified.
566                 *            Must not be negative.
567                 *
568                 * @return This builder.
569                 */
570                public Builder pbes2Count(final int p2c) {
571
572                        if (p2c < 0)
573                                throw new IllegalArgumentException("The PBES2 count parameter must not be negative");
574
575                        this.p2c = p2c;
576                        return this;
577                }
578
579
580                /**
581                 * Sets the initialisation vector ({@code iv}) parameter.
582                 *
583                 * @param iv The initialisation vector, {@code null} if not
584                 *           specified.
585                 *
586                 * @return This builder.
587                 */
588                public Builder iv(final Base64URL iv) {
589
590                        this.iv = iv;
591                        return this;
592                }
593
594
595                /**
596                 * Sets the authentication tag ({@code tag}) parameter.
597                 *
598                 * @param tag The authentication tag, {@code null} if not
599                 *            specified.
600                 *
601                 * @return This builder.
602                 */
603                public Builder authTag(final Base64URL tag) {
604
605                        this.tag = tag;
606                        return this;
607                }
608
609
610                /**
611                 * Sets a custom (non-registered) parameter.
612                 *
613                 * @param name  The name of the custom parameter. Must not
614                 *              match a registered parameter name and must not
615                 *              be {@code null}.
616                 * @param value The value of the custom parameter, should map
617                 *              to a valid JSON entity, {@code null} if not
618                 *              specified.
619                 *
620                 * @return This builder.
621                 *
622                 * @throws IllegalArgumentException If the specified parameter
623                 *                                  name matches a registered
624                 *                                  parameter name.
625                 */
626                public Builder customParam(final String name, final Object value) {
627
628                        if (getRegisteredParameterNames().contains(name)) {
629                                throw new IllegalArgumentException("The parameter name \"" + name + "\" matches a registered name");
630                        }
631
632                        if (customParams == null) {
633                                customParams = new HashMap<>();
634                        }
635
636                        customParams.put(name, value);
637
638                        return this;
639                }
640
641
642                /**
643                 * Sets the custom (non-registered) parameters. The values must
644                 * be serialisable to a JSON entity, otherwise will be ignored.
645                 *
646                 * @param customParameters The custom parameters, empty map or
647                 *                         {@code null} if none.
648                 *
649                 * @return This builder.
650                 */
651                public Builder customParams(final Map<String, Object> customParameters) {
652
653                        this.customParams = customParameters;
654                        return this;
655                }
656
657
658                /**
659                 * Sets the parsed Base64URL.
660                 *
661                 * @param base64URL The parsed Base64URL, {@code null} if the
662                 *                  header is created from scratch.
663                 *
664                 * @return This builder.
665                 */
666                public Builder parsedBase64URL(final Base64URL base64URL) {
667
668                        this.parsedBase64URL = base64URL;
669                        return this;
670                }
671
672
673                /**
674                 * Builds a new JWE header.
675                 *
676                 * @return The JWE header.
677                 */
678                public JWEHeader build() {
679
680                        return new JWEHeader(
681                                alg, enc, typ, cty, crit,
682                                jku, jwk, x5u, x5t, x5t256, x5c, kid,
683                                epk, zip, apu, apv, p2s, p2c,
684                                iv, tag,
685                                customParams, parsedBase64URL);
686                }
687        }
688
689
690        /**
691         * The encryption method ({@code enc}) parameter.
692         */
693        private final EncryptionMethod enc;
694
695
696        /**
697         * The ephemeral public key ({@code epk}) parameter.
698         */
699        private final JWK epk;
700
701
702        /**
703         * The compression algorithm ({@code zip}) parameter.
704         */
705        private final CompressionAlgorithm zip;
706
707
708        /**
709         * The agreement PartyUInfo ({@code apu}) parameter.
710         */
711        private final Base64URL apu;
712        
713        
714        /**
715         * The agreement PartyVInfo ({@code apv}) parameter.
716         */
717        private final Base64URL apv;
718
719
720        /**
721         * The PBES2 salt ({@code p2s}) parameter.
722         */
723        private final Base64URL p2s;
724
725
726        /**
727         * The PBES2 count ({@code p2c}) parameter.
728         */
729        private final int p2c;
730
731
732        /**
733         * The initialisation vector ({@code iv}) parameter.
734         */
735        private final Base64URL iv;
736
737
738        /**
739         * The authentication tag ({@code tag}) parameter.
740         */
741        private final Base64URL tag;
742
743
744        /**
745         * Creates a new minimal JSON Web Encryption (JWE) header.
746         *
747         * <p>Note: Use {@link PlainHeader} to create a header with algorithm
748         * {@link Algorithm#NONE none}.
749         *
750         * @param alg The JWE algorithm parameter. Must not be "none" or
751         *            {@code null}.
752         * @param enc The encryption method parameter. Must not be 
753         *            {@code null}.
754         */
755        public JWEHeader(final JWEAlgorithm alg, final EncryptionMethod enc) {
756
757                this(
758                        alg, enc,
759                        null, null, null, null, null, null, null, null, null, null,
760                        null, null, null, null, null, 0,
761                        null, null,
762                        null, null);
763        }
764
765
766        /**
767         * Creates a new JSON Web Encryption (JWE) header.
768         *
769         * <p>Note: Use {@link PlainHeader} to create a header with algorithm
770         * {@link Algorithm#NONE none}.
771         *
772         * @param alg             The JWE algorithm ({@code alg}) parameter.
773         *                        Must not be "none" or {@code null}.
774         * @param enc             The encryption method parameter. Must not be
775         *                        {@code null}.
776         * @param typ             The type ({@code typ}) parameter,
777         *                        {@code null} if not specified.
778         * @param cty             The content type ({@code cty}) parameter,
779         *                        {@code null} if not specified.
780         * @param crit            The names of the critical header
781         *                        ({@code crit}) parameters, empty set or
782         *                        {@code null} if none.
783         * @param jku             The JSON Web Key (JWK) Set URL ({@code jku})
784         *                        parameter, {@code null} if not specified.
785         * @param jwk             The X.509 certificate URL ({@code jwk})
786         *                        parameter, {@code null} if not specified.
787         * @param x5u             The X.509 certificate URL parameter
788         *                        ({@code x5u}), {@code null} if not specified.
789         * @param x5t             The X.509 certificate SHA-1 thumbprint
790         *                        ({@code x5t}) parameter, {@code null} if not
791         *                        specified.
792         * @param x5t256          The X.509 certificate SHA-256 thumbprint
793         *                        ({@code x5t#S256}) parameter, {@code null} if
794         *                        not specified.
795         * @param x5c             The X.509 certificate chain ({@code x5c})
796         *                        parameter, {@code null} if not specified.
797         * @param kid             The key ID ({@code kid}) parameter,
798         *                        {@code null} if not specified.
799         * @param epk             The Ephemeral Public Key ({@code epk})
800         *                        parameter, {@code null} if not specified.
801         * @param zip             The compression algorithm ({@code zip})
802         *                        parameter, {@code null} if not specified.
803         * @param apu             The agreement PartyUInfo ({@code apu})
804         *                        parameter, {@code null} if not specified.
805         * @param apv             The agreement PartyVInfo ({@code apv})
806         *                        parameter, {@code null} if not specified.
807         * @param p2s             The PBES2 salt ({@code p2s}) parameter,
808         *                        {@code null} if not specified.
809         * @param p2c             The PBES2 count ({@code p2c}) parameter, zero
810         *                        if not specified. Must not be negative.
811         * @param iv              The initialisation vector ({@code iv})
812         *                        parameter, {@code null} if not specified.
813         * @param tag             The authentication tag ({@code tag})
814         *                        parameter, {@code null} if not specified.
815         * @param customParams    The custom parameters, empty map or
816         *                        {@code null} if none.
817         * @param parsedBase64URL The parsed Base64URL, {@code null} if the
818         *                        header is created from scratch.
819         */
820        public JWEHeader(final Algorithm alg,
821                         final EncryptionMethod enc,
822                         final JOSEObjectType typ,
823                         final String cty,
824                         final Set<String> crit,
825                         final URI jku,
826                         final JWK jwk,
827                         final URI x5u,
828                         final Base64URL x5t,
829                         final Base64URL x5t256,
830                         final List<Base64> x5c,
831                         final String kid,
832                         final JWK epk,
833                         final CompressionAlgorithm zip,
834                         final Base64URL apu,
835                         final Base64URL apv,
836                         final Base64URL p2s,
837                         final int p2c,
838                         final Base64URL iv,
839                         final Base64URL tag,
840                         final Map<String,Object> customParams,
841                         final Base64URL parsedBase64URL) {
842
843                super(alg, typ, cty, crit, jku, jwk, x5u, x5t, x5t256, x5c, kid, customParams, parsedBase64URL);
844
845                if (alg.getName().equals(Algorithm.NONE.getName())) {
846                        throw new IllegalArgumentException("The JWE algorithm cannot be \"none\"");
847                }
848
849                if (enc == null) {
850                        throw new IllegalArgumentException("The encryption method \"enc\" parameter must not be null");
851                }
852
853                if (epk != null && epk.isPrivate()) {
854                        throw new IllegalArgumentException("Ephemeral public key should not be a private key");
855                }
856
857                this.enc = enc;
858
859                this.epk = epk;
860                this.zip = zip;
861                this.apu = apu;
862                this.apv = apv;
863                this.p2s = p2s;
864                this.p2c = p2c;
865                this.iv = iv;
866                this.tag = tag;
867        }
868
869
870        /**
871         * Deep copy constructor.
872         *
873         * @param jweHeader The JWE header to copy. Must not be {@code null}.
874         */
875        public JWEHeader(final JWEHeader jweHeader) {
876
877                this(
878                        jweHeader.getAlgorithm(),
879                        jweHeader.getEncryptionMethod(),
880                        jweHeader.getType(),
881                        jweHeader.getContentType(),
882                        jweHeader.getCriticalParams(),
883                        jweHeader.getJWKURL(),
884                        jweHeader.getJWK(),
885                        jweHeader.getX509CertURL(),
886                        jweHeader.getX509CertThumbprint(),
887                        jweHeader.getX509CertSHA256Thumbprint(),
888                        jweHeader.getX509CertChain(),
889                        jweHeader.getKeyID(),
890                        jweHeader.getEphemeralPublicKey(),
891                        jweHeader.getCompressionAlgorithm(),
892                        jweHeader.getAgreementPartyUInfo(),
893                        jweHeader.getAgreementPartyVInfo(),
894                        jweHeader.getPBES2Salt(),
895                        jweHeader.getPBES2Count(),
896                        jweHeader.getIV(),
897                        jweHeader.getAuthTag(),
898                        jweHeader.getCustomParams(),
899                        jweHeader.getParsedBase64URL()
900                );
901        }
902
903
904        /**
905         * Gets the registered parameter names for JWE headers.
906         *
907         * @return The registered parameter names, as an unmodifiable set.
908         */
909        public static Set<String> getRegisteredParameterNames() {
910
911                return REGISTERED_PARAMETER_NAMES;
912        }
913
914
915        /**
916         * Gets the algorithm ({@code alg}) parameter.
917         *
918         * @return The algorithm parameter.
919         */
920        @Override
921        public JWEAlgorithm getAlgorithm() {
922
923                return (JWEAlgorithm)super.getAlgorithm();
924        }
925
926
927        /**
928         * Gets the encryption method ({@code enc}) parameter.
929         *
930         * @return The encryption method parameter.
931         */
932        public EncryptionMethod getEncryptionMethod() {
933
934                return enc;
935        }
936
937
938        /**
939         * Gets the Ephemeral Public Key ({@code epk}) parameter.
940         *
941         * @return The Ephemeral Public Key parameter, {@code null} if not
942         *         specified.
943         */
944        public JWK getEphemeralPublicKey() {
945
946                return epk;
947        }
948
949
950        /**
951         * Gets the compression algorithm ({@code zip}) parameter.
952         *
953         * @return The compression algorithm parameter, {@code null} if not
954         *         specified.
955         */
956        public CompressionAlgorithm getCompressionAlgorithm() {
957
958                return zip;
959        }
960
961
962        /**
963         * Gets the agreement PartyUInfo ({@code apu}) parameter.
964         *
965         * @return The agreement PartyUInfo parameter, {@code null} if not
966         *         specified.
967         */
968        public Base64URL getAgreementPartyUInfo() {
969
970                return apu;
971        }
972
973
974        /**
975         * Gets the agreement PartyVInfo ({@code apv}) parameter.
976         *
977         * @return The agreement PartyVInfo parameter, {@code null} if not
978         *         specified.
979         */
980        public Base64URL getAgreementPartyVInfo() {
981
982                return apv;
983        }
984
985
986        /**
987         * Gets the PBES2 salt ({@code p2s}) parameter.
988         *
989         * @return The PBES2 salt parameter, {@code null} if not specified.
990         */
991        public Base64URL getPBES2Salt() {
992
993                return p2s;
994        }
995
996
997        /**
998         * Gets the PBES2 count ({@code p2c}) parameter.
999         *
1000         * @return The PBES2 count parameter, zero if not specified.
1001         */
1002        public int getPBES2Count() {
1003
1004                return p2c;
1005        }
1006
1007
1008        /**
1009         * Gets the initialisation vector ({@code iv}) parameter.
1010         *
1011         * @return The initialisation vector, {@code null} if not specified.
1012         */
1013        public Base64URL getIV() {
1014
1015                return iv;
1016        }
1017
1018
1019        /**
1020         * Gets the authentication tag ({@code tag}) parameter.
1021         *
1022         * @return The authentication tag, {@code null} if not specified.
1023         */
1024        public Base64URL getAuthTag() {
1025
1026                return tag;
1027        }
1028
1029
1030        @Override
1031        public Set<String> getIncludedParams() {
1032
1033                Set<String> includedParameters = super.getIncludedParams();
1034
1035                if (enc != null) {
1036                        includedParameters.add(HeaderParameterNames.ENCRYPTION_ALGORITHM);
1037                }
1038
1039                if (epk != null) {
1040                        includedParameters.add(HeaderParameterNames.EPHEMERAL_PUBLIC_KEY);
1041                }
1042
1043                if (zip != null) {
1044                        includedParameters.add(HeaderParameterNames.COMPRESSION_ALGORITHM);
1045                }
1046
1047                if (apu != null) {
1048                        includedParameters.add(HeaderParameterNames.AGREEMENT_PARTY_U_INFO);
1049                }
1050                
1051                if (apv != null) {
1052                        includedParameters.add(HeaderParameterNames.AGREEMENT_PARTY_V_INFO);
1053                }
1054
1055                if (p2s != null) {
1056                        includedParameters.add(HeaderParameterNames.PBES2_SALT_INPUT);
1057                }
1058
1059                if (p2c > 0) {
1060                        includedParameters.add(HeaderParameterNames.PBES2_COUNT);
1061                }
1062
1063                if (iv != null) {
1064                        includedParameters.add(HeaderParameterNames.INITIALIZATION_VECTOR);
1065                }
1066
1067                if (tag != null) {
1068                        includedParameters.add(HeaderParameterNames.AUTHENTICATION_TAG);
1069                }
1070
1071                return includedParameters;
1072        }
1073
1074
1075        @Override
1076        public Map<String, Object> toJSONObject() {
1077
1078                Map<String, Object> o = super.toJSONObject();
1079
1080                if (enc != null) {
1081                        o.put(HeaderParameterNames.ENCRYPTION_ALGORITHM, enc.toString());
1082                }
1083
1084                if (epk != null) {
1085                        o.put(HeaderParameterNames.EPHEMERAL_PUBLIC_KEY, epk.toJSONObject());
1086                }
1087
1088                if (zip != null) {
1089                        o.put(HeaderParameterNames.COMPRESSION_ALGORITHM, zip.toString());
1090                }
1091
1092                if (apu != null) {
1093                        o.put(HeaderParameterNames.AGREEMENT_PARTY_U_INFO, apu.toString());
1094                }
1095                
1096                if (apv != null) {
1097                        o.put(HeaderParameterNames.AGREEMENT_PARTY_V_INFO, apv.toString());
1098                }
1099
1100                if (p2s != null) {
1101                        o.put(HeaderParameterNames.PBES2_SALT_INPUT, p2s.toString());
1102                }
1103
1104                if (p2c > 0) {
1105                        o.put(HeaderParameterNames.PBES2_COUNT, p2c);
1106                }
1107
1108                if (iv != null) {
1109                        o.put(HeaderParameterNames.INITIALIZATION_VECTOR, iv.toString());
1110                }
1111
1112                if (tag != null) {
1113                        o.put(HeaderParameterNames.AUTHENTICATION_TAG, tag.toString());
1114                }
1115
1116                return o;
1117        }
1118
1119
1120        /**
1121         * Parses an encryption method ({@code enc}) parameter from the 
1122         * specified JWE header JSON object.
1123         *
1124         * @param json The JSON object to parse. Must not be {@code null}.
1125         *
1126         * @return The encryption method.
1127         *
1128         * @throws ParseException If the {@code enc} parameter couldn't be 
1129         *                        parsed.
1130         */
1131        private static EncryptionMethod parseEncryptionMethod(final Map<String, Object> json)
1132                throws ParseException {
1133
1134                return EncryptionMethod.parse(JSONObjectUtils.getString(json, HeaderParameterNames.ENCRYPTION_ALGORITHM));
1135        }
1136
1137
1138        /**
1139         * Parses a JWE header from the specified JSON object.
1140         *
1141         * @param jsonObject The JSON object to parse. Must not be
1142         *                   {@code null}.
1143         *
1144         * @return The JWE header.
1145         *
1146         * @throws ParseException If the specified JSON object doesn't
1147         *                        represent a valid JWE header.
1148         */
1149        public static JWEHeader parse(final Map<String, Object> jsonObject)
1150                throws ParseException {
1151
1152                return parse(jsonObject, null);
1153        }
1154
1155
1156        /**
1157         * Parses a JWE header from the specified JSON object.
1158         *
1159         * @param jsonObject      The JSON object to parse. Must not be
1160         *                        {@code null}.
1161         * @param parsedBase64URL The original parsed Base64URL, {@code null}
1162         *                        if not applicable.
1163         *
1164         * @return The JWE header.
1165         *
1166         * @throws ParseException If the specified JSON object doesn't 
1167         *                        represent a valid JWE header.
1168         */
1169        public static JWEHeader parse(final Map<String, Object> jsonObject,
1170                                      final Base64URL parsedBase64URL)
1171                throws ParseException {
1172
1173                // Get the "alg" parameter
1174                Algorithm alg = Header.parseAlgorithm(jsonObject);
1175
1176                if (! (alg instanceof JWEAlgorithm)) {
1177                        throw new ParseException("The algorithm \"alg\" header parameter must be for encryption", 0);
1178                }
1179
1180                // Get the "enc" parameter
1181                EncryptionMethod enc = parseEncryptionMethod(jsonObject);
1182
1183                JWEHeader.Builder header = new Builder((JWEAlgorithm)alg, enc).parsedBase64URL(parsedBase64URL);
1184
1185                // Parse optional + custom parameters
1186                for(final String name: jsonObject.keySet()) {
1187
1188                        if(HeaderParameterNames.ALGORITHM.equals(name)) {
1189                                // skip
1190                        } else if(HeaderParameterNames.ENCRYPTION_ALGORITHM.equals(name)) {
1191                                // skip
1192                        } else if(HeaderParameterNames.TYPE.equals(name)) {
1193                                String typValue = JSONObjectUtils.getString(jsonObject, name);
1194                                if (typValue != null) {
1195                                        header = header.type(new JOSEObjectType(typValue));
1196                                }
1197                        } else if(HeaderParameterNames.CONTENT_TYPE.equals(name)) {
1198                                header = header.contentType(JSONObjectUtils.getString(jsonObject, name));
1199                        } else if(HeaderParameterNames.CRITICAL.equals(name)) {
1200                                List<String> critValues = JSONObjectUtils.getStringList(jsonObject, name);
1201                                if (critValues != null) {
1202                                        header = header.criticalParams(new HashSet<>(critValues));
1203                                }
1204                        } else if(HeaderParameterNames.JWK_SET_URL.equals(name)) {
1205                                header = header.jwkURL(JSONObjectUtils.getURI(jsonObject, name));
1206                        } else if(HeaderParameterNames.JWK.equals(name)) {
1207                                Map<String, Object> jwkObject = JSONObjectUtils.getJSONObject(jsonObject, name);
1208                                if (jwkObject != null) {
1209                                        header = header.jwk(JWK.parse(jwkObject));
1210                                }
1211                        } else if(HeaderParameterNames.X_509_CERT_URL.equals(name)) {
1212                                header = header.x509CertURL(JSONObjectUtils.getURI(jsonObject, name));
1213                        } else if(HeaderParameterNames.X_509_CERT_SHA_1_THUMBPRINT.equals(name)) {
1214                                header = header.x509CertThumbprint(Base64URL.from(JSONObjectUtils.getString(jsonObject, name)));
1215                        } else if(HeaderParameterNames.X_509_CERT_SHA_256_THUMBPRINT.equals(name)) {
1216                                header = header.x509CertSHA256Thumbprint(Base64URL.from(JSONObjectUtils.getString(jsonObject, name)));
1217                        } else if(HeaderParameterNames.X_509_CERT_CHAIN.equals(name)) {
1218                                header = header.x509CertChain(X509CertChainUtils.toBase64List(JSONObjectUtils.getJSONArray(jsonObject, name)));
1219                        } else if(HeaderParameterNames.KEY_ID.equals(name)) {
1220                                header = header.keyID(JSONObjectUtils.getString(jsonObject, name));
1221                        } else if(HeaderParameterNames.EPHEMERAL_PUBLIC_KEY.equals(name)) {
1222                                header = header.ephemeralPublicKey(JWK.parse(JSONObjectUtils.getJSONObject(jsonObject, name)));
1223                        } else if(HeaderParameterNames.COMPRESSION_ALGORITHM.equals(name)) {
1224                                String zipValue = JSONObjectUtils.getString(jsonObject, name);
1225                                if (zipValue != null) {
1226                                        header = header.compressionAlgorithm(new CompressionAlgorithm(zipValue));
1227                                }
1228                        } else if(HeaderParameterNames.AGREEMENT_PARTY_U_INFO.equals(name)) {
1229                                header = header.agreementPartyUInfo(Base64URL.from(JSONObjectUtils.getString(jsonObject, name)));
1230                        } else if(HeaderParameterNames.AGREEMENT_PARTY_V_INFO.equals(name)) {
1231                                header = header.agreementPartyVInfo(Base64URL.from(JSONObjectUtils.getString(jsonObject, name)));
1232                        } else if(HeaderParameterNames.PBES2_SALT_INPUT.equals(name)) {
1233                                header = header.pbes2Salt(Base64URL.from(JSONObjectUtils.getString(jsonObject, name)));
1234                        } else if(HeaderParameterNames.PBES2_COUNT.equals(name)) {
1235                                header = header.pbes2Count(JSONObjectUtils.getInt(jsonObject, name));
1236                        } else if(HeaderParameterNames.INITIALIZATION_VECTOR.equals(name)) {
1237                                header = header.iv(Base64URL.from(JSONObjectUtils.getString(jsonObject, name)));
1238                        } else if(HeaderParameterNames.AUTHENTICATION_TAG.equals(name)) {
1239                                header = header.authTag(Base64URL.from(JSONObjectUtils.getString(jsonObject, name)));
1240                        } else {
1241                                header = header.customParam(name, jsonObject.get(name));
1242                        }
1243                }
1244
1245                return header.build();
1246        }
1247
1248
1249        /**
1250         * Parses a JWE header from the specified JSON object string.
1251         *
1252         * @param jsonString The JSON object string to parse. Must not be {@code null}.
1253         *
1254         * @return The JWE header.
1255         *
1256         * @throws ParseException If the specified JSON object string doesn't 
1257         *                        represent a valid JWE header.
1258         */
1259        public static JWEHeader parse(final String jsonString)
1260                throws ParseException {
1261
1262                return parse(JSONObjectUtils.parse(jsonString), null);
1263        }
1264
1265
1266        /**
1267         * Parses a JWE header from the specified JSON object string.
1268         *
1269         * @param jsonString      The JSON string to parse. Must not be
1270         *                        {@code null}.
1271         * @param parsedBase64URL The original parsed Base64URL, {@code null}
1272         *                        if not applicable.
1273         *
1274         * @return The JWE header.
1275         *
1276         * @throws ParseException If the specified JSON object string doesn't
1277         *                        represent a valid JWE header.
1278         */
1279        public static JWEHeader parse(final String jsonString,
1280                                      final Base64URL parsedBase64URL)
1281                throws ParseException {
1282
1283                return parse(JSONObjectUtils.parse(jsonString, MAX_HEADER_STRING_LENGTH), parsedBase64URL);
1284        }
1285
1286
1287        /**
1288         * Parses a JWE header from the specified Base64URL.
1289         *
1290         * @param base64URL The Base64URL to parse. Must not be {@code null}.
1291         *
1292         * @return The JWE header.
1293         *
1294         * @throws ParseException If the specified Base64URL doesn't represent
1295         *                        a valid JWE header.
1296         */
1297        public static JWEHeader parse(final Base64URL base64URL)
1298                throws ParseException {
1299
1300                return parse(base64URL.decodeToString(), base64URL);
1301        }
1302}