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}