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