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