001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2019, 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.jwk;
019
020
021import java.util.*;
022
023import com.nimbusds.jose.Algorithm;
024import com.nimbusds.jose.JWEHeader;
025import com.nimbusds.jose.JWSAlgorithm;
026import com.nimbusds.jose.JWSHeader;
027import com.nimbusds.jose.util.Base64URL;
028import net.jcip.annotations.Immutable;
029
030
031/**
032 * JSON Web Key (JWK) matcher. May be used to ensure a JWK matches a set of
033 * application-specific criteria.
034 *
035 * <p>Supported key matching criteria:
036 *
037 * <ul>
038 *     <li>Any, unspecified, one or more key types (typ).
039 *     <li>Any, unspecified, one or more key uses (use).
040 *     <li>Any, unspecified, one or more key operations (key_ops).
041 *     <li>Any, unspecified, one or more key algorithms (alg).
042 *     <li>Any, unspecified, one or more key identifiers (kid).
043 *     <li>Private only key.
044 *     <li>Public only key.
045 *     <li>Minimum, maximum or exact key sizes.
046 *     <li>Any, unspecified, one or more curves for EC and OKP keys (crv).
047 *     <li>X.509 certificate SHA-256 thumbprint.
048 * </ul>
049 *
050 * <p>Matching by JWK thumbprint (RFC 7638), X.509 certificate URL and X.509
051 * certificate chain is not supported.
052 *
053 * @author Vladimir Dzhuvinov
054 * @author Josh Cummings
055 * @author Ben Arena
056 * @version 2020-05-19
057 */
058@Immutable
059public class JWKMatcher {
060
061
062        /**
063         * The key types to match.
064         */
065        private final Set<KeyType> types;
066
067
068        /**
069         * The public key uses to match.
070         */
071        private final Set<KeyUse> uses;
072
073
074        /**
075         * The key operations to match.
076         */
077        private final Set<KeyOperation> ops;
078
079
080        /**
081         * The algorithms to match.
082         */
083        private final Set<Algorithm> algs;
084
085
086        /**
087         * The key IDs to match.
088         */
089        private final Set<String> ids;
090        
091        
092        /**
093         * {@code true} to match a key with a set use.
094         */
095        private final boolean hasUse;
096        
097        
098        /**
099         * {@code true} to match a key with a set ID.
100         */
101        private final boolean hasID;
102
103
104        /**
105         * {@code true} to match a private key.
106         */
107        private final boolean privateOnly;
108
109
110        /**
111         * {@code true} to match a public only key.
112         */
113        private final boolean publicOnly;
114
115
116        /**
117         * The minimum key size in bits, zero implies no minimum size limit.
118         */
119        private final int minSizeBits;
120
121
122        /**
123         * The maximum key size in bits, zero implies no maximum size limit.
124         */
125        private final int maxSizeBits;
126        
127        
128        /**
129         * The key sizes in bits.
130         */
131        private final Set<Integer> sizesBits;
132        
133        
134        /**
135         * The curves to match (for EC and OKP keys).
136         */
137        private final Set<Curve> curves;
138
139        
140        /**
141         * The X.509 certificate SHA-256 thumbprints to match.
142         */
143        private final Set<Base64URL> x5tS256s;
144
145        
146        /**
147         * Builder for constructing JWK matchers.
148         *
149         * <p>Example usage:
150         *
151         * <pre>
152         * JWKMatcher matcher = new JWKMatcher().keyID("123").build();
153         * </pre>
154         */
155        public static class Builder {
156
157                
158                /**
159                 * The key types to match.
160                 */
161                private Set<KeyType> types;
162
163
164                /**
165                 * The public key uses to match.
166                 */
167                private Set<KeyUse> uses;
168
169
170                /**
171                 * The key operations to match.
172                 */
173                private Set<KeyOperation> ops;
174
175
176                /**
177                 * The algorithms to match.
178                 */
179                private Set<Algorithm> algs;
180
181
182                /**
183                 * The key IDs to match.
184                 */
185                private Set<String> ids;
186                
187                
188                /**
189                 * {@code true} to match a key with a set use.
190                 */
191                private boolean hasUse = false;
192                
193                
194                /**
195                 * {@code true} to match a key with a set ID.
196                 */
197                private boolean hasID = false;
198
199
200                /**
201                 * {@code true} to match a private key.
202                 */
203                private boolean privateOnly = false;
204
205
206                /**
207                 * {@code true} to match a public only key.
208                 */
209                private boolean publicOnly = false;
210
211
212                /**
213                 * The minimum key size in bits, zero implies no minimum size
214                 * limit.
215                 */
216                private int minSizeBits = 0;
217
218
219                /**
220                 * The maximum key size in bits, zero implies no maximum size
221                 * limit.
222                 */
223                private int maxSizeBits = 0;
224                
225                
226                /**
227                 * The key sizes in bits.
228                 */
229                private Set<Integer> sizesBits;
230                
231                
232                /**
233                 * The curves to match (for EC and OKP keys).
234                 */
235                private Set<Curve> curves;
236
237                
238                /**
239                 * The X.509 certificate SHA-256 thumbprints to match.
240                 */
241                private Set<Base64URL> x5tS256s;
242
243                
244                /**
245                 * Sets a single key type to match.
246                 *
247                 * @param kty The key type, {@code null} if not specified.
248                 *            
249                 * @return This builder.            
250                 */
251                public Builder keyType(final KeyType kty) {
252
253                        if (kty == null) {
254                                types = null;
255                        } else {
256                                types = new HashSet<>(Collections.singletonList(kty));
257                        }
258                        
259                        return this;
260                }
261
262
263                /**
264                 * Sets multiple key types to match.
265                 *
266                 * @param types The key types.
267                 *
268                 * @return This builder.
269                 */
270                public Builder keyTypes(final KeyType ... types) {
271
272                        keyTypes(new LinkedHashSet<>(Arrays.asList(types)));
273                        return this;
274                }
275
276
277                /**
278                 * Sets multiple key types to match.
279                 *
280                 * @param types The key types, {@code null} if not specified.
281                 *
282                 * @return This builder.
283                 */
284                public Builder keyTypes(final Set<KeyType> types) {
285
286                        this.types = types;
287                        return this;
288                }
289
290
291                /**
292                 * Sets a single public key use to match.
293                 *
294                 * @param use The public key use, {@code null} if not 
295                 *            specified.
296                 *
297                 * @return This builder.
298                 */
299                public Builder keyUse(final KeyUse use) {
300
301                        if (use == null) {
302                                uses = null;
303                        } else {
304                                uses = new HashSet<>(Collections.singletonList(use));
305                        }
306                        return this;
307                }
308
309
310                /**
311                 * Sets multiple public key uses to match.
312                 *
313                 * @param uses The public key uses.
314                 *
315                 * @return This builder.
316                 */
317                public Builder keyUses(final KeyUse... uses) {
318
319                        keyUses(new LinkedHashSet<>(Arrays.asList(uses)));
320                        return this;
321                }
322
323
324                /**
325                 * Sets multiple public key uses to match.
326                 *
327                 * @param uses The public key uses, {@code null} if not
328                 *             specified.
329                 *
330                 * @return This builder.
331                 */
332                public Builder keyUses(final Set<KeyUse> uses) {
333
334                        this.uses = uses;
335                        return this;
336                }
337
338
339                /**
340                 * Sets a single key operation to match.
341                 *
342                 * @param op The key operation, {@code null} if not specified.
343                 *
344                 * @return This builder.
345                 */
346                public Builder keyOperation(final KeyOperation op) {
347
348                        if (op == null) {
349                                ops = null;
350                        } else {
351                                ops = new HashSet<>(Collections.singletonList(op));
352                        }
353                        return this;
354                }
355
356
357                /**
358                 * Sets multiple key operations to match.
359                 *
360                 * @param ops The key operations.
361                 *
362                 * @return This builder.
363                 */
364                public Builder keyOperations(final KeyOperation... ops) {
365
366                        keyOperations(new LinkedHashSet<>(Arrays.asList(ops)));
367                        return this;
368                }
369
370
371                /**
372                 * Sets multiple key operations to match.
373                 *
374                 * @param ops The key operations, {@code null} if not
375                 *            specified.
376                 *
377                 * @return This builder.
378                 */
379                public Builder keyOperations(final Set<KeyOperation> ops) {
380
381                        this.ops = ops;
382                        return this;
383                }
384
385
386                /**
387                 * Sets a single JOSE algorithm to match.
388                 *
389                 * @param alg The JOSE algorithm, {@code null} if not
390                 *            specified.
391                 *
392                 * @return This builder.
393                 */
394                public Builder algorithm(final Algorithm alg) {
395
396                        if (alg == null) {
397                                algs = null;
398                        } else {
399                                algs = new HashSet<>(Collections.singletonList(alg));
400                        }
401                        return this;
402                }
403
404
405                /**
406                 * Sets multiple JOSE algorithms to match.
407                 *
408                 * @param algs The JOSE algorithms.
409                 *
410                 * @return This builder.
411                 */
412                public Builder algorithms(final Algorithm ... algs) {
413
414                        algorithms(new LinkedHashSet<>(Arrays.asList(algs)));
415                        return this;
416                }
417
418
419                /**
420                 * Sets multiple JOSE algorithms to match.
421                 *
422                 * @param algs The JOSE algorithms, {@code null} if not
423                 *             specified.
424                 *
425                 * @return This builder.
426                 */
427                public Builder algorithms(final Set<Algorithm> algs) {
428
429                        this.algs = algs;
430                        return this;
431                }
432
433
434                /**
435                 * Sets a single key ID to match.
436                 *
437                 * @param id The key ID, {@code null} if not specified.
438                 *
439                 * @return This builder.
440                 */
441                public Builder keyID(final String id) {
442
443                        if (id == null) {
444                                ids = null;
445                        } else {
446                                ids = new HashSet<>(Collections.singletonList(id));
447                        }
448                        return this;
449                }
450
451
452                /**
453                 * Sets multiple key IDs to match.
454                 *
455                 * @param ids The key IDs.
456                 *
457                 * @return This builder.
458                 */
459                public Builder keyIDs(final String ... ids) {
460
461                        keyIDs(new LinkedHashSet<>(Arrays.asList(ids)));
462                        return this;
463                }
464
465
466                /**
467                 * Sets multiple key IDs to match.
468                 *
469                 * @param ids The key IDs, {@code null} if not specified.
470                 *
471                 * @return This builder.
472                 */
473                public Builder keyIDs(final Set<String> ids) {
474
475                        this.ids = ids;
476                        return this;
477                }
478                
479                
480                /**
481                 * Sets key use presence matching.
482                 *
483                 * @param hasUse {@code true} to match a key with a set use.
484                 *
485                 * @return This builder.
486                 */
487                public Builder hasKeyUse(final boolean hasUse) {
488                        
489                        this.hasUse = hasUse;
490                        return this;
491                }
492                
493                
494                /**
495                 * Sets key ID presence matching.
496                 *
497                 * @param hasID {@code true} to match a key with a set ID.
498                 *
499                 * @return This builder.
500                 */
501                public Builder hasKeyID(final boolean hasID) {
502                        
503                        this.hasID = hasID;
504                        return this;
505                }
506
507
508                /**
509                 * Sets the private key matching policy.
510                 *
511                 * @param privateOnly {@code true} to match a private key.
512                 *
513                 * @return This builder.
514                 */
515                public Builder privateOnly(final boolean privateOnly) {
516
517                        this.privateOnly = privateOnly;
518                        return this;
519                }
520
521
522                /**
523                 * Sets the public key matching policy.
524                 *
525                 * @param publicOnly {@code true} to match a public only key.
526                 *
527                 * @return This builder.
528                 */
529                public Builder publicOnly(final boolean publicOnly) {
530
531                        this.publicOnly = publicOnly;
532                        return this;
533                }
534
535
536                /**
537                 * Sets the minimal key size.
538                 *
539                 * @param minSizeBits The minimum key size in bits, zero
540                 *                    implies no minimum key size limit.
541                 *
542                 * @return This builder.
543                 */
544                public Builder minKeySize(final int minSizeBits) {
545
546                        this.minSizeBits = minSizeBits;
547                        return this;
548                }
549
550
551                /**
552                 * Sets the maximum key size.
553                 *
554                 * @param maxSizeBits The maximum key size in bits, zero
555                 *                    implies no maximum key size limit.
556                 *
557                 * @return This builder.
558                 */
559                public Builder maxKeySize(final int maxSizeBits) {
560
561                        this.maxSizeBits = maxSizeBits;
562                        return this;
563                }
564                
565                
566                /**
567                 * Sets the key size.
568                 *
569                 * @param keySizeBits The key size in bits, zero if not
570                 *                    specified.
571                 *
572                 * @return This builder.
573                 */
574                public Builder keySize(final int keySizeBits) {
575                        if (keySizeBits <= 0) {
576                                sizesBits = null;
577                        } else {
578                                sizesBits = Collections.singleton(keySizeBits);
579                        }
580                        return this;
581                }
582                
583                
584                /**
585                 * Sets the key sizes.
586                 *
587                 * @param keySizesBits The key sizes in bits.
588                 *
589                 * @return This builder.
590                 */
591                public Builder keySizes(final int... keySizesBits) {
592                        Set<Integer> sizesSet = new LinkedHashSet<>();
593                        for (int keySize: keySizesBits) {
594                                sizesSet.add(keySize);
595                        }
596                        keySizes(sizesSet);
597                        return this;
598                }
599                
600                
601                /**
602                 * Sets the key sizes.
603                 *
604                 * @param keySizesBits The key sizes in bits.
605                 *
606                 * @return This builder.
607                 */
608                public Builder keySizes(final Set<Integer> keySizesBits) {
609                        
610                        this.sizesBits = keySizesBits;
611                        return this;
612                }
613                
614                
615                /**
616                 * Sets a single curve to match (for EC and OKP keys).
617                 *
618                 * @param curve The curve, {@code null} if not specified.
619                 *
620                 * @return This builder.
621                 */
622                public Builder curve(final Curve curve) {
623                        
624                        if (curve == null) {
625                                curves = null;
626                        } else {
627                                curves = Collections.singleton(curve);
628                        }
629                        return this;
630                }
631                
632                
633                /**
634                 * Sets multiple curves to match (for EC and OKP keys).
635                 *
636                 * @param curves The curves.
637                 *
638                 * @return This builder.
639                 */
640                public Builder curves(final Curve... curves) {
641                        
642                        curves(new LinkedHashSet<>(Arrays.asList(curves)));
643                        return this;
644                }
645                
646                
647                /**
648                 * Sets multiple curves to match (for EC and OKP keys).
649                 *
650                 * @param curves The curves, {@code null} if not specified.
651                 *
652                 * @return This builder.
653                 */
654                public Builder curves(final Set<Curve> curves) {
655                        
656                        this.curves = curves;
657                        return this;
658                }
659
660                
661                /**
662                 * Sets a single X.509 certificate SHA-256 thumbprint to match.
663                 *
664                 * @param x5tS256 The thumbprint, {@code null} if not
665                 *                specified.
666                 *
667                 * @return This builder.
668                 */
669                public Builder x509CertSHA256Thumbprint(final Base64URL x5tS256) {
670
671                        if (x5tS256 == null) {
672                                x5tS256s = null;
673                        } else {
674                                x5tS256s = Collections.singleton(x5tS256);
675                        }
676                        return this;
677                }
678
679                /**
680                 * Sets multiple X.509 certificate SHA-256 thumbprints to
681                 * match.
682                 *
683                 * @param x5tS256s The thumbprints.
684                 *
685                 * @return This builder.
686                 */
687                public Builder x509CertSHA256Thumbprints(final Base64URL... x5tS256s) {
688                        return x509CertSHA256Thumbprints(new LinkedHashSet<>(Arrays.asList(x5tS256s)));
689                }
690
691                
692                /**
693                 * Sets multiple X.509 certificate SHA-256 thumbprints to
694                 * match.
695                 *
696                 * @param x5tS256s The thumbprints, {@code null} if not
697                 *                 specified.
698                 *
699                 * @return This builder.
700                 */
701                public Builder x509CertSHA256Thumbprints(final Set<Base64URL> x5tS256s) {
702                        this.x5tS256s = x5tS256s;
703                        return this;
704                }
705
706                /**
707                 * Builds a new JWK matcher.
708                 *
709                 * @return The JWK matcher.
710                 */
711                public JWKMatcher build() {
712
713                        return new JWKMatcher(types, uses, ops, algs, ids, hasUse, hasID, privateOnly, publicOnly, minSizeBits, maxSizeBits, sizesBits, curves, x5tS256s);
714                }
715        }
716
717
718        /**
719         * Creates a new JSON Web Key (JWK) matcher.
720         *
721         * @param types       The key types to match, {@code null} if not
722         *                    specified.
723         * @param uses        The public key uses to match, {@code null} if not
724         *                    specified.
725         * @param ops         The key operations to match, {@code null} if not
726         *                    specified.
727         * @param algs        The JOSE algorithms to match, {@code null} if not
728         *                    specified.
729         * @param ids         The key IDs to match, {@code null} if not
730         *                    specified.
731         * @param privateOnly {@code true} to match a private key.
732         * @param publicOnly  {@code true} to match a public only key.
733         */
734        @Deprecated
735        public JWKMatcher(final Set<KeyType> types,
736                          final Set<KeyUse> uses,
737                          final Set<KeyOperation> ops,
738                          final Set<Algorithm> algs,
739                          final Set<String> ids,
740                          final boolean privateOnly,
741                          final boolean publicOnly) {
742
743                this(types, uses, ops, algs, ids, privateOnly, publicOnly, 0, 0);
744        }
745
746
747        /**
748         * Creates a new JSON Web Key (JWK) matcher.
749         *
750         * @param types       The key types to match, {@code null} if not
751         *                    specified.
752         * @param uses        The public key uses to match, {@code null} if not
753         *                    specified.
754         * @param ops         The key operations to match, {@code null} if not
755         *                    specified.
756         * @param algs        The JOSE algorithms to match, {@code null} if not
757         *                    specified.
758         * @param ids         The key IDs to match, {@code null} if not
759         *                    specified.
760         * @param privateOnly {@code true} to match a private key.
761         * @param publicOnly  {@code true} to match a public only key.
762         * @param minSizeBits The minimum key size in bits, zero implies no
763         *                    minimum size limit.
764         * @param maxSizeBits The maximum key size in bits, zero implies no
765         *                    maximum size limit.
766         */
767        @Deprecated
768        public JWKMatcher(final Set<KeyType> types,
769                          final Set<KeyUse> uses,
770                          final Set<KeyOperation> ops,
771                          final Set<Algorithm> algs,
772                          final Set<String> ids,
773                          final boolean privateOnly,
774                          final boolean publicOnly,
775                          final int minSizeBits,
776                          final int maxSizeBits) {
777                
778                this(types, uses, ops, algs, ids, privateOnly, publicOnly, minSizeBits, maxSizeBits, null);
779        }
780
781
782        /**
783         * Creates a new JSON Web Key (JWK) matcher.
784         *
785         * @param types       The key types to match, {@code null} if not
786         *                    specified.
787         * @param uses        The public key uses to match, {@code null} if not
788         *                    specified.
789         * @param ops         The key operations to match, {@code null} if not
790         *                    specified.
791         * @param algs        The JOSE algorithms to match, {@code null} if not
792         *                    specified.
793         * @param ids         The key IDs to match, {@code null} if not
794         *                    specified.
795         * @param privateOnly {@code true} to match a private key.
796         * @param publicOnly  {@code true} to match a public only key.
797         * @param minSizeBits The minimum key size in bits, zero implies no
798         *                    minimum size limit.
799         * @param maxSizeBits The maximum key size in bits, zero implies no
800         *                    maximum size limit.
801         * @param curves      The curves to match (for EC keys), {@code null}
802         *                    if not specified.
803         */
804        @Deprecated
805        public JWKMatcher(final Set<KeyType> types,
806                          final Set<KeyUse> uses,
807                          final Set<KeyOperation> ops,
808                          final Set<Algorithm> algs,
809                          final Set<String> ids,
810                          final boolean privateOnly,
811                          final boolean publicOnly,
812                          final int minSizeBits,
813                          final int maxSizeBits,
814                          final Set<Curve> curves) {
815                
816                this(types, uses, ops, algs, ids, privateOnly, publicOnly, minSizeBits, maxSizeBits, null, curves);
817        }
818
819
820        /**
821         * Creates a new JSON Web Key (JWK) matcher.
822         *
823         * @param types       The key types to match, {@code null} if not
824         *                    specified.
825         * @param uses        The public key uses to match, {@code null} if not
826         *                    specified.
827         * @param ops         The key operations to match, {@code null} if not
828         *                    specified.
829         * @param algs        The JOSE algorithms to match, {@code null} if not
830         *                    specified.
831         * @param ids         The key IDs to match, {@code null} if not
832         *                    specified.
833         * @param privateOnly {@code true} to match a private key.
834         * @param publicOnly  {@code true} to match a public only key.
835         * @param minSizeBits The minimum key size in bits, zero implies no
836         *                    minimum size limit.
837         * @param maxSizeBits The maximum key size in bits, zero implies no
838         *                    maximum size limit.
839         * @param sizesBits   The key sizes in bits, {@code null} if not
840         *                    specified.
841         * @param curves      The curves to match (for EC and OKP keys),
842         *                    {@code null} if not specified.
843         */
844        @Deprecated
845        public JWKMatcher(final Set<KeyType> types,
846                          final Set<KeyUse> uses,
847                          final Set<KeyOperation> ops,
848                          final Set<Algorithm> algs,
849                          final Set<String> ids,
850                          final boolean privateOnly,
851                          final boolean publicOnly,
852                          final int minSizeBits,
853                          final int maxSizeBits,
854                          final Set<Integer> sizesBits,
855                          final Set<Curve> curves) {
856                
857                this(types, uses, ops, algs, ids, false, false, privateOnly, publicOnly, minSizeBits, maxSizeBits, sizesBits, curves);
858        }
859
860
861        /**
862         * Creates a new JSON Web Key (JWK) matcher.
863         *
864         * @param types       The key types to match, {@code null} if not
865         *                    specified.
866         * @param uses        The public key uses to match, {@code null} if not
867         *                    specified.
868         * @param ops         The key operations to match, {@code null} if not
869         *                    specified.
870         * @param algs        The JOSE algorithms to match, {@code null} if not
871         *                    specified.
872         * @param ids         The key IDs to match, {@code null} if not
873         *                    specified.
874         * @param hasUse      {@code true} to match a key with a set use.
875         * @param hasID       {@code true} to match a key with a set ID.
876         * @param privateOnly {@code true} to match a private key.
877         * @param publicOnly  {@code true} to match a public only key.
878         * @param minSizeBits The minimum key size in bits, zero implies no
879         *                    minimum size limit.
880         * @param maxSizeBits The maximum key size in bits, zero implies no
881         *                    maximum size limit.
882         * @param sizesBits   The key sizes in bits, {@code null} if not
883         *                    specified.
884         * @param curves      The curves to match (for EC and OKP keys),
885         *                    {@code null} if not specified.
886         */
887        @Deprecated
888        public JWKMatcher(final Set<KeyType> types,
889                          final Set<KeyUse> uses,
890                          final Set<KeyOperation> ops,
891                          final Set<Algorithm> algs,
892                          final Set<String> ids,
893                          final boolean hasUse,
894                          final boolean hasID,
895                          final boolean privateOnly,
896                          final boolean publicOnly,
897                          final int minSizeBits,
898                          final int maxSizeBits,
899                          final Set<Integer> sizesBits,
900                          final Set<Curve> curves) {
901
902                this(types, uses, ops, algs, ids, hasUse, hasID, privateOnly, publicOnly, minSizeBits, maxSizeBits, sizesBits, curves, null);
903        }
904
905        /**
906         * Creates a new JSON Web Key (JWK) matcher.
907         *
908         * @param types       The key types to match, {@code null} if not
909         *                    specified.
910         * @param uses        The public key uses to match, {@code null} if not
911         *                    specified.
912         * @param ops         The key operations to match, {@code null} if not
913         *                    specified.
914         * @param algs        The JOSE algorithms to match, {@code null} if not
915         *                    specified.
916         * @param ids         The key IDs to match, {@code null} if not
917         *                    specified.
918         * @param hasUse      {@code true} to match a key with a set use.
919         * @param hasID       {@code true} to match a key with a set ID.
920         * @param privateOnly {@code true} to match a private key.
921         * @param publicOnly  {@code true} to match a public only key.
922         * @param minSizeBits The minimum key size in bits, zero implies no
923         *                    minimum size limit.
924         * @param maxSizeBits The maximum key size in bits, zero implies no
925         *                    maximum size limit.
926         * @param sizesBits   The key sizes in bits, {@code null} if not
927         *                    specified.
928         * @param curves      The curves to match (for EC and OKP keys),
929         *                    {@code null} if not specified.
930         * @param x5tS256s    The X.509 certificate thumbprints to match,
931         *                    {@code null} if not specified.
932         */
933        public JWKMatcher(final Set<KeyType> types,
934                                          final Set<KeyUse> uses,
935                                          final Set<KeyOperation> ops,
936                                          final Set<Algorithm> algs,
937                                          final Set<String> ids,
938                                          final boolean hasUse,
939                                          final boolean hasID,
940                                          final boolean privateOnly,
941                                          final boolean publicOnly,
942                                          final int minSizeBits,
943                                          final int maxSizeBits,
944                                          final Set<Integer> sizesBits,
945                                          final Set<Curve> curves,
946                                          final Set<Base64URL> x5tS256s) {
947
948                this.types = types;
949                this.uses = uses;
950                this.ops = ops;
951                this.algs = algs;
952                this.ids = ids;
953                this.hasUse = hasUse;
954                this.hasID = hasID;
955                this.privateOnly = privateOnly;
956                this.publicOnly = publicOnly;
957                this.minSizeBits = minSizeBits;
958                this.maxSizeBits = maxSizeBits;
959                this.sizesBits = sizesBits;
960                this.curves = curves;
961                this.x5tS256s = x5tS256s;
962        }
963
964        /**
965         * Returns a {@link JWKMatcher} based on the given {@link JWEHeader}.
966         *
967         * <p>The {@link JWKMatcher} is configured as follows:
968         *
969         * <ul>
970         *     <li>The key type to match is determined by the JWE algorithm
971         *         (alg).
972         *     <li>The key ID to match is set by the JWE header key ID (kid)
973         *         parameter (if set).
974         *     <li>The key uses to match are set to encryption or not
975         *         specified.
976         *     <li>The key algorithm to match is set to the JWE algorithm (alg)
977         *         or not specified.
978         * </ul>
979         *
980         * <p>Other JWE header parameters are not taken into account.
981         *
982         * @param jweHeader The header to use.
983         *
984         * @return A {@code JWKMatcher} based on the given header.
985         */
986        public static JWKMatcher forJWEHeader(final JWEHeader jweHeader) {
987
988                return new JWKMatcher.Builder()
989                        .keyType(KeyType.forAlgorithm(jweHeader.getAlgorithm()))
990                        .keyID(jweHeader.getKeyID())
991                        .keyUses(KeyUse.ENCRYPTION, null)
992                        .algorithms(jweHeader.getAlgorithm(), null)
993                        .build();
994        }
995
996        /**
997         * Returns a {@link JWKMatcher} based on the given {@link JWSHeader}.
998         *
999         * <p>The {@link JWKMatcher} is configured as follows:
1000         *
1001         * <ul>
1002         *     <li>The key type to match is determined by the JWS algorithm
1003         *         (alg).
1004         *     <li>The key ID to match is set by the JWS header key ID (kid)
1005         *         parameter (if set).
1006         *     <li>The key uses to match are set to signature or not specified.
1007         *     <li>The key algorithm to match is set to the JWS algorithm (alg)
1008         *         or not specified.
1009         *     <li>The X.509 certificate SHA-256 thumbprint to match is set to
1010         *         the x5t#S256 parameter (if set).
1011         * </ul>
1012         *
1013         * <p>Other JWS header parameters are not taken into account.
1014         *
1015         * @param jwsHeader The header to use.
1016         *
1017         * @return A {@code JWKMatcher} based on the given header, {@code null}
1018         *         if the JWS algorithm is not supported.
1019         */
1020        public static JWKMatcher forJWSHeader(final JWSHeader jwsHeader) {
1021
1022                JWSAlgorithm algorithm = jwsHeader.getAlgorithm();
1023                if (JWSAlgorithm.Family.RSA.contains(algorithm) || JWSAlgorithm.Family.EC.contains(algorithm)) {
1024                        // RSA or EC key matcher
1025                        return new JWKMatcher.Builder()
1026                                .keyType(KeyType.forAlgorithm(algorithm))
1027                                .keyID(jwsHeader.getKeyID())
1028                                .keyUses(KeyUse.SIGNATURE, null)
1029                                .algorithms(algorithm, null)
1030                                .x509CertSHA256Thumbprint(jwsHeader.getX509CertSHA256Thumbprint())
1031                                .build();
1032                } else if (JWSAlgorithm.Family.HMAC_SHA.contains(algorithm)) {
1033                        // HMAC secret matcher
1034                        return new JWKMatcher.Builder()
1035                                .keyType(KeyType.forAlgorithm(algorithm))
1036                                .keyID(jwsHeader.getKeyID())
1037                                .privateOnly(true)
1038                                .algorithms(algorithm, null)
1039                                .build();
1040                } else if (JWSAlgorithm.Family.ED.contains(algorithm)) {
1041                        return new JWKMatcher.Builder()
1042                                .keyType(KeyType.forAlgorithm(algorithm))
1043                                .keyID(jwsHeader.getKeyID())
1044                                .keyUses(KeyUse.SIGNATURE, null)
1045                                .algorithms(algorithm, null)
1046                                .curves(Curve.forJWSAlgorithm(algorithm))
1047                                .build();
1048                } else {
1049                        return null; // Unsupported algorithm
1050                }
1051        }
1052
1053        /**
1054         * Returns the key types to match.
1055         *
1056         * @return The key types, {@code null} if not specified.
1057         */
1058        public Set<KeyType> getKeyTypes() {
1059
1060                return types;
1061        }
1062
1063
1064        /**
1065         * Returns the public key uses to match.
1066         *
1067         * @return The public key uses, {@code null} if not specified.
1068         */
1069        public Set<KeyUse> getKeyUses() {
1070
1071                return uses;
1072        }
1073
1074
1075        /**
1076         * Returns the key operations to match.
1077         *
1078         * @return The key operations, {@code null} if not specified.
1079         */
1080        public Set<KeyOperation> getKeyOperations() {
1081
1082                return ops;
1083        }
1084
1085
1086        /**
1087         * Returns the JOSE algorithms to match.
1088         *
1089         * @return The JOSE algorithms, {@code null} if not specified.
1090         */
1091        public Set<Algorithm> getAlgorithms() {
1092
1093                return algs;
1094        }
1095
1096
1097        /**
1098         * Returns the key IDs to match.
1099         *
1100         * @return The key IDs, {@code null} if not specified.
1101         */
1102        public Set<String> getKeyIDs() {
1103
1104                return ids;
1105        }
1106        
1107        
1108        /**
1109         * Returns {@code true} if keys with a set use are matched.
1110         *
1111         * @return {@code true} if keys with a set use are matched, else
1112         *         {@code false}.
1113         */
1114        public boolean hasKeyUse() {
1115                
1116                return hasUse;
1117        }
1118        
1119        
1120        /**
1121         * Returns {@code true} if keys with a set use are matched.
1122         *
1123         * @return {@code true} if keys with a set ID are matched, else
1124         *         {@code false}.
1125         */
1126        public boolean hasKeyID() {
1127                
1128                return hasID;
1129        }
1130
1131
1132        /**
1133         * Returns {@code true} if only private keys are matched.
1134         *
1135         * @return {@code true} if only private keys are matched, else 
1136         *         {@code false}.
1137         */
1138        public boolean isPrivateOnly() {
1139
1140                return privateOnly;
1141        }
1142
1143
1144        /**
1145         * Returns {@code true} if only public keys are matched.
1146         *
1147         * @return {@code true} if only public keys are selected, else
1148         *         {@code false}.
1149         */
1150        public boolean isPublicOnly() {
1151
1152                return publicOnly;
1153        }
1154
1155
1156        /**
1157         * Returns the minimum key size. Use {@link #getMinKeySize()} instead.
1158         *
1159         * @return The minimum key size in bits, zero implies no minimum size
1160         *         limit.
1161         */
1162        @Deprecated
1163        public int getMinSize() {
1164
1165                return getMinKeySize();
1166        }
1167
1168
1169        /**
1170         * Returns the minimum key size.
1171         *
1172         * @return The minimum key size in bits, zero implies no minimum size
1173         *         limit.
1174         */
1175        public int getMinKeySize() {
1176
1177                return minSizeBits;
1178        }
1179
1180
1181        /**
1182         * Returns the maximum key size. Use {@link #getMaxKeySize()} instead.
1183         *
1184         * @return The maximum key size in bits, zero implies no maximum size
1185         *         limit.
1186         */
1187        @Deprecated
1188        public int getMaxSize() {
1189
1190                return getMaxKeySize();
1191        }
1192
1193
1194        /**
1195         * Returns the maximum key size.
1196         *
1197         * @return The maximum key size in bits, zero implies no maximum size
1198         *         limit.
1199         */
1200        public int getMaxKeySize() {
1201
1202                return maxSizeBits;
1203        }
1204        
1205        
1206        /**
1207         * Returns the key sizes.
1208         *
1209         * @return The key sizes in bits, {@code null} if not specified.
1210         */
1211        public Set<Integer> getKeySizes() {
1212                
1213                return sizesBits;
1214        }
1215        
1216        
1217        /**
1218         * Returns the curves to match (for EC and OKP keys).
1219         *
1220         * @return The curves, {@code null} if not specified.
1221         */
1222        public Set<Curve> getCurves() {
1223                
1224                return curves;
1225        }
1226
1227        /**
1228         * Returns the X.509 certificate SHA-256 thumbprints to match.
1229         *
1230         * @return The thumbprints, {@code null} if not specified.
1231         */
1232        public Set<Base64URL> getX509CertSHA256Thumbprints() {
1233                
1234                return x5tS256s;
1235        }
1236
1237        /**
1238         * Returns {@code true} if the specified JWK matches.
1239         *
1240         * @param key The JSON Web Key (JWK). Must not  be {@code null}.
1241         *
1242         * @return {@code true} if the JWK matches, else {@code false}.
1243         */
1244        public boolean matches(final JWK key) {
1245                
1246                if (hasUse && key.getKeyUse() == null)
1247                        return false;
1248                
1249                if (hasID && (key.getKeyID() == null || key.getKeyID().trim().isEmpty()))
1250                        return false;
1251
1252                if (privateOnly && ! key.isPrivate())
1253                        return false;
1254
1255                if (publicOnly && key.isPrivate())
1256                        return false;
1257
1258                if (types != null && ! types.contains(key.getKeyType()))
1259                        return false;
1260
1261                if (uses != null && ! uses.contains(key.getKeyUse()))
1262                        return false;
1263
1264                if (ops != null) {
1265
1266                        if (ops.contains(null) && key.getKeyOperations() == null) {
1267                                // pass
1268                        } else if (key.getKeyOperations() != null && ops.containsAll(key.getKeyOperations())) {
1269                                // pass
1270                        } else {
1271                                return false;
1272                        }
1273                }
1274
1275                if (algs != null && ! algs.contains(key.getAlgorithm()))
1276                        return false;
1277
1278                if (ids != null && ! ids.contains(key.getKeyID()))
1279                        return false;
1280
1281                if (minSizeBits > 0) {
1282
1283                        if (key.size() < minSizeBits)
1284                                return false;
1285                }
1286
1287                if (maxSizeBits > 0) {
1288
1289                        if (key.size() > maxSizeBits)
1290                                return false;
1291                }
1292                
1293                if (sizesBits != null) {
1294                        if (! sizesBits.contains(key.size()))
1295                                return false;
1296                }
1297                
1298                if (curves != null) {
1299                        
1300                        if (! (key instanceof CurveBasedJWK))
1301                                return false;
1302                        
1303                        CurveBasedJWK curveBasedJWK = (CurveBasedJWK) key;
1304                        
1305                        if (! curves.contains(curveBasedJWK.getCurve()))
1306                                return false;
1307                }
1308
1309                if (x5tS256s != null) {
1310                        return x5tS256s.contains(key.getX509CertSHA256Thumbprint());
1311                }
1312
1313                return true;
1314        }
1315        
1316        @Override
1317        public String toString() {
1318                StringBuilder sb = new StringBuilder();
1319                
1320                append(sb, "kty", types);
1321                append(sb, "use", uses);
1322                append(sb, "key_ops", ops);
1323                append(sb, "alg", algs);
1324                append(sb, "kid", ids);
1325                
1326                if (hasUse) {
1327                        sb.append("has_use=true ");
1328                }
1329                
1330                if (hasID) {
1331                        sb.append("has_id=true ");
1332                }
1333                
1334                if (privateOnly) {
1335                        sb.append("private_only=true ");
1336                }
1337                
1338                if (publicOnly) {
1339                        sb.append("public_only=true ");
1340                }
1341                
1342                if (minSizeBits > 0) {
1343                        sb.append("min_size=" + minSizeBits + " ");
1344                }
1345                
1346                if (maxSizeBits > 0) {
1347                        sb.append("max_size=" + maxSizeBits + " ");
1348                }
1349                
1350                append(sb, "size", sizesBits);
1351                append(sb, "crv", curves);
1352                append(sb, "x5t#S256", x5tS256s);
1353                        
1354                return sb.toString().trim();
1355        }
1356        
1357        
1358        /**
1359         * Appends the specified JWK matcher parameter to a string builder.
1360         *
1361         * @param sb     The string builder. Must not be {@code null}.
1362         * @param key    The parameter key. Must not be {@code null}.
1363         * @param values The parameter value, {@code null} if not specified.
1364         */
1365        private static void append(final StringBuilder sb, final String key, final Set<?> values) {
1366                
1367                if (values != null) {
1368                        
1369                        sb.append(key);
1370                        sb.append('=');
1371                        if (values.size() == 1) {
1372                                Object value = values.iterator().next();
1373                                if (value == null) {
1374                                        sb.append("ANY");
1375                                } else {
1376                                        sb.append(value.toString().trim());
1377                                }
1378                        } else {
1379                                sb.append(values.toString().trim());
1380                        }
1381                        
1382                        sb.append(' ');
1383                }
1384        }
1385}