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