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