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