001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2016, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.jwk; 019 020 021import java.math.BigInteger; 022import java.net.URI; 023import java.security.*; 024import java.security.cert.Certificate; 025import java.security.cert.CertificateEncodingException; 026import java.security.cert.X509Certificate; 027import java.security.interfaces.ECPrivateKey; 028import java.security.interfaces.ECPublicKey; 029import java.security.spec.*; 030import java.text.ParseException; 031import java.util.*; 032 033import net.jcip.annotations.Immutable; 034import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 035 036import com.nimbusds.jose.Algorithm; 037import com.nimbusds.jose.JOSEException; 038import com.nimbusds.jose.crypto.utils.ECChecks; 039import com.nimbusds.jose.util.Base64; 040import com.nimbusds.jose.util.Base64URL; 041import com.nimbusds.jose.util.BigIntegerUtils; 042import com.nimbusds.jose.util.JSONObjectUtils; 043 044 045/** 046 * Public and private {@link KeyType#EC Elliptic Curve} JSON Web Key (JWK). 047 * This class is immutable. 048 * 049 * <p>Supported curves: 050 * 051 * <ul> 052 * <li>{@link Curve#P_256 P-256} 053 * <li>{@link Curve#SECP256K1 secp256k1} 054 * <li>{@link Curve#P_384 P-384} 055 * <li>{@link Curve#P_521 P-512} 056 * </ul> 057 * 058 * <p>Provides EC JWK import from / export to the following standard Java 059 * interfaces and classes: 060 * 061 * <ul> 062 * <li>{@link java.security.interfaces.ECPublicKey} 063 * <li>{@link java.security.interfaces.ECPrivateKey} 064 * <li>{@link java.security.PrivateKey} for an EC key in a PKCS#11 store 065 * <li>{@link java.security.KeyPair} 066 * </ul> 067 * 068 * <p>Example JSON object representation of a public EC JWK: 069 * 070 * <pre> 071 * { 072 * "kty" : "EC", 073 * "crv" : "P-256", 074 * "x" : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", 075 * "y" : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", 076 * "use" : "enc", 077 * "kid" : "1" 078 * } 079 * </pre> 080 * 081 * <p>Example JSON object representation of a private EC JWK: 082 * 083 * <pre> 084 * { 085 * "kty" : "EC", 086 * "crv" : "P-256", 087 * "x" : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", 088 * "y" : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", 089 * "d" : "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE", 090 * "use" : "enc", 091 * "kid" : "1" 092 * } 093 * </pre> 094 * 095 * <p>Use the builder to create a new EC JWK: 096 * 097 * <pre> 098 * ECKey key = new ECKey.Builder(Curve.P_256, x, y) 099 * .keyUse(KeyUse.SIGNATURE) 100 * .keyID("1") 101 * .build(); 102 * </pre> 103 * 104 * <p>See http://en.wikipedia.org/wiki/Elliptic_curve_cryptography 105 * 106 * @author Vladimir Dzhuvinov 107 * @author Justin Richer 108 * @version 2022-12-26 109 */ 110@Immutable 111public final class ECKey extends JWK implements AsymmetricJWK, CurveBasedJWK { 112 113 114 private static final long serialVersionUID = 1L; 115 116 117 /** 118 * Supported EC curves. 119 */ 120 public static final Set<Curve> SUPPORTED_CURVES = Collections.unmodifiableSet( 121 new HashSet<>(Arrays.asList(Curve.P_256, Curve.SECP256K1, Curve.P_384, Curve.P_521)) 122 ); 123 124 125 /** 126 * Builder for constructing Elliptic Curve JWKs. 127 * 128 * <p>Example usage: 129 * 130 * <pre> 131 * ECKey key = new ECKey.Builder(Curve.P521, x, y) 132 * .d(d) 133 * .algorithm(JWSAlgorithm.ES512) 134 * .keyID("1") 135 * .build(); 136 * </pre> 137 */ 138 public static class Builder { 139 140 141 /** 142 * The curve name. 143 */ 144 private final Curve crv; 145 146 147 /** 148 * The public 'x' EC coordinate. 149 */ 150 private final Base64URL x; 151 152 153 /** 154 * The public 'y' EC coordinate. 155 */ 156 private final Base64URL y; 157 158 159 /** 160 * The private 'd' EC coordinate, optional. 161 */ 162 private Base64URL d; 163 164 165 /** 166 * The private EC key, as PKCS#11 handle, optional. 167 */ 168 private PrivateKey priv; 169 170 171 /** 172 * The key use, optional. 173 */ 174 private KeyUse use; 175 176 177 /** 178 * The key operations, optional. 179 */ 180 private Set<KeyOperation> ops; 181 182 183 /** 184 * The intended JOSE algorithm for the key, optional. 185 */ 186 private Algorithm alg; 187 188 189 /** 190 * The key ID, optional. 191 */ 192 private String kid; 193 194 195 /** 196 * X.509 certificate URL, optional. 197 */ 198 private URI x5u; 199 200 201 /** 202 * X.509 certificate SHA-1 thumbprint, optional. 203 */ 204 @Deprecated 205 private Base64URL x5t; 206 207 208 /** 209 * X.509 certificate SHA-256 thumbprint, optional. 210 */ 211 private Base64URL x5t256; 212 213 214 /** 215 * The X.509 certificate chain, optional. 216 */ 217 private List<Base64> x5c; 218 219 220 /** 221 * The key expiration time, optional. 222 */ 223 private Date exp; 224 225 226 /** 227 * The key not-before time, optional. 228 */ 229 private Date nbf; 230 231 232 /** 233 * The key issued-at time, optional. 234 */ 235 private Date iat; 236 237 238 /** 239 * Reference to the underlying key store, {@code null} if none. 240 */ 241 private KeyStore ks; 242 243 244 /** 245 * Creates a new Elliptic Curve JWK builder. 246 * 247 * @param crv The cryptographic curve. Must not be 248 * {@code null}. 249 * @param x The public 'x' coordinate for the elliptic curve 250 * point. It is represented as the Base64URL 251 * encoding of the coordinate's big endian 252 * representation. Must not be {@code null}. 253 * @param y The public 'y' coordinate for the elliptic curve 254 * point. It is represented as the Base64URL 255 * encoding of the coordinate's big endian 256 * representation. Must not be {@code null}. 257 */ 258 public Builder(final Curve crv, final Base64URL x, final Base64URL y) { 259 260 if (crv == null) { 261 throw new IllegalArgumentException("The curve must not be null"); 262 } 263 264 this.crv = crv; 265 266 if (x == null) { 267 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 268 } 269 270 this.x = x; 271 272 if (y == null) { 273 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 274 } 275 276 this.y = y; 277 } 278 279 280 /** 281 * Creates a new Elliptic Curve JWK builder. 282 * 283 * @param crv The cryptographic curve. Must not be 284 * {@code null}. 285 * @param pub The public EC key to represent. Must not be 286 * {@code null}. 287 */ 288 public Builder(final Curve crv, final ECPublicKey pub) { 289 290 this(crv, 291 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 292 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY())); 293 } 294 295 296 /** 297 * Creates a new Elliptic Curve JWK builder. 298 * 299 * @param ecJWK The EC JWK to start with. Must not be 300 * {@code null}. 301 */ 302 public Builder(final ECKey ecJWK) { 303 304 crv = ecJWK.crv; 305 x = ecJWK.x; 306 y = ecJWK.y; 307 d = ecJWK.d; 308 priv = ecJWK.privateKey; 309 use = ecJWK.getKeyUse(); 310 ops = ecJWK.getKeyOperations(); 311 alg = ecJWK.getAlgorithm(); 312 kid = ecJWK.getKeyID(); 313 x5u = ecJWK.getX509CertURL(); 314 x5t = ecJWK.getX509CertThumbprint(); 315 x5t256 = ecJWK.getX509CertSHA256Thumbprint(); 316 x5c = ecJWK.getX509CertChain(); 317 exp = ecJWK.getExpirationTime(); 318 nbf = ecJWK.getNotBeforeTime(); 319 iat = ecJWK.getIssueTime(); 320 ks = ecJWK.getKeyStore(); 321 } 322 323 324 /** 325 * Sets the private 'd' coordinate for the elliptic curve 326 * point. The alternative method is {@link #privateKey}. 327 * 328 * @param d The private 'd' coordinate. It is represented as 329 * the Base64URL encoding of the coordinate's big 330 * endian representation. {@code null} if not 331 * specified (for a public key). 332 * 333 * @return This builder. 334 */ 335 public Builder d(final Base64URL d) { 336 337 this.d = d; 338 return this; 339 } 340 341 342 /** 343 * Sets the private Elliptic Curve key. The alternative method 344 * is {@link #d}. 345 * 346 * @param priv The private EC key, used to obtain the private 347 * 'd' coordinate for the elliptic curve point. 348 * {@code null} if not specified (for a public 349 * key). 350 * 351 * @return This builder. 352 */ 353 public Builder privateKey(final ECPrivateKey priv) { 354 355 if (priv != null) { 356 this.d = encodeCoordinate(priv.getParams().getCurve().getField().getFieldSize(), priv.getS()); 357 } 358 359 return this; 360 } 361 362 363 /** 364 * Sets the private EC key, typically for a key located in a 365 * PKCS#11 store that doesn't expose the private key parameters 366 * (such as a smart card or HSM). 367 * 368 * @param priv The private EC key reference. Its algorithm must 369 * be "EC". Must not be {@code null}. 370 * 371 * @return This builder. 372 */ 373 public Builder privateKey(final PrivateKey priv) { 374 375 if (priv instanceof ECPrivateKey) { 376 return privateKey((ECPrivateKey) priv); 377 } 378 379 if (! "EC".equalsIgnoreCase(priv.getAlgorithm())) { 380 throw new IllegalArgumentException("The private key algorithm must be EC"); 381 } 382 383 this.priv = priv; 384 return this; 385 } 386 387 388 /** 389 * Sets the use ({@code use}) of the JWK. 390 * 391 * @param use The key use, {@code null} if not specified or if 392 * the key is intended for signing as well as 393 * encryption. 394 * 395 * @return This builder. 396 */ 397 public Builder keyUse(final KeyUse use) { 398 399 this.use = use; 400 return this; 401 } 402 403 404 /** 405 * Sets the operations ({@code key_ops}) of the JWK. 406 * 407 * @param ops The key operations, {@code null} if not 408 * specified. 409 * 410 * @return This builder. 411 */ 412 public Builder keyOperations(final Set<KeyOperation> ops) { 413 414 this.ops = ops; 415 return this; 416 } 417 418 419 /** 420 * Sets the intended JOSE algorithm ({@code alg}) for the JWK. 421 * 422 * @param alg The intended JOSE algorithm, {@code null} if not 423 * specified. 424 * 425 * @return This builder. 426 */ 427 public Builder algorithm(final Algorithm alg) { 428 429 this.alg = alg; 430 return this; 431 } 432 433 /** 434 * Sets the ID ({@code kid}) of the JWK. The key ID can be used 435 * to match a specific key. This can be used, for instance, to 436 * choose a key within a {@link JWKSet} during key rollover. 437 * The key ID may also correspond to a JWS/JWE {@code kid} 438 * header parameter value. 439 * 440 * @param kid The key ID, {@code null} if not specified. 441 * 442 * @return This builder. 443 */ 444 public Builder keyID(final String kid) { 445 446 this.kid = kid; 447 return this; 448 } 449 450 451 /** 452 * Sets the ID ({@code kid}) of the JWK to its SHA-256 JWK 453 * thumbprint (RFC 7638). The key ID can be used to match a 454 * specific key. This can be used, for instance, to choose a 455 * key within a {@link JWKSet} during key rollover. The key ID 456 * may also correspond to a JWS/JWE {@code kid} header 457 * parameter value. 458 * 459 * @return This builder. 460 * 461 * @throws JOSEException If the SHA-256 hash algorithm is not 462 * supported. 463 */ 464 public Builder keyIDFromThumbprint() 465 throws JOSEException { 466 467 return keyIDFromThumbprint("SHA-256"); 468 } 469 470 471 /** 472 * Sets the ID ({@code kid}) of the JWK to its JWK thumbprint 473 * (RFC 7638). The key ID can be used to match a specific key. 474 * This can be used, for instance, to choose a key within a 475 * {@link JWKSet} during key rollover. The key ID may also 476 * correspond to a JWS/JWE {@code kid} header parameter value. 477 * 478 * @param hashAlg The hash algorithm for the JWK thumbprint 479 * computation. Must not be {@code null}. 480 * 481 * @return This builder. 482 * 483 * @throws JOSEException If the hash algorithm is not 484 * supported. 485 */ 486 public Builder keyIDFromThumbprint(final String hashAlg) 487 throws JOSEException { 488 489 // Put mandatory params in sorted order 490 LinkedHashMap<String,String> requiredParams = new LinkedHashMap<>(); 491 requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE, crv.toString()); 492 requiredParams.put(JWKParameterNames.KEY_TYPE, KeyType.EC.getValue()); 493 requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE_X_COORDINATE, x.toString()); 494 requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE_Y_COORDINATE, y.toString()); 495 this.kid = ThumbprintUtils.compute(hashAlg, requiredParams).toString(); 496 return this; 497 } 498 499 500 /** 501 * Sets the X.509 certificate URL ({@code x5u}) of the JWK. 502 * 503 * @param x5u The X.509 certificate URL, {@code null} if not 504 * specified. 505 * 506 * @return This builder. 507 */ 508 public Builder x509CertURL(final URI x5u) { 509 510 this.x5u = x5u; 511 return this; 512 } 513 514 515 /** 516 * Sets the X.509 certificate SHA-1 thumbprint ({@code x5t}) of 517 * the JWK. 518 * 519 * @param x5t The X.509 certificate SHA-1 thumbprint, 520 * {@code null} if not specified. 521 * 522 * @return This builder. 523 */ 524 @Deprecated 525 public Builder x509CertThumbprint(final Base64URL x5t) { 526 527 this.x5t = x5t; 528 return this; 529 } 530 531 532 /** 533 * Sets the X.509 certificate SHA-256 thumbprint 534 * ({@code x5t#S256}) of the JWK. 535 * 536 * @param x5t256 The X.509 certificate SHA-256 thumbprint, 537 * {@code null} if not specified. 538 * 539 * @return This builder. 540 */ 541 public Builder x509CertSHA256Thumbprint(final Base64URL x5t256) { 542 543 this.x5t256 = x5t256; 544 return this; 545 } 546 547 548 /** 549 * Sets the X.509 certificate chain ({@code x5c}) of the JWK. 550 * 551 * @param x5c The X.509 certificate chain as a unmodifiable 552 * list, {@code null} if not specified. 553 * 554 * @return This builder. 555 */ 556 public Builder x509CertChain(final List<Base64> x5c) { 557 558 this.x5c = x5c; 559 return this; 560 } 561 562 563 /** 564 * Sets the expiration time ({@code exp}) of the JWK. 565 * 566 * @param exp The expiration time, {@code null} if not 567 * specified. 568 * 569 * @return This builder. 570 */ 571 public Builder expirationTime(final Date exp) { 572 573 this.exp = exp; 574 return this; 575 } 576 577 578 /** 579 * Sets the not-before time ({@code nbf}) of the JWK. 580 * 581 * @param nbf The not-before time, {@code null} if not 582 * specified. 583 * 584 * @return This builder. 585 */ 586 public Builder notBeforeTime(final Date nbf) { 587 588 this.nbf = nbf; 589 return this; 590 } 591 592 593 /** 594 * Sets the issued-at time ({@code iat}) of the JWK. 595 * 596 * @param iat The issued-at time, {@code null} if not 597 * specified. 598 * 599 * @return This builder. 600 */ 601 public Builder issueTime(final Date iat) { 602 603 this.iat = iat; 604 return this; 605 } 606 607 608 /** 609 * Sets the underlying key store. 610 * 611 * @param keyStore Reference to the underlying key store, 612 * {@code null} if none. 613 * 614 * @return This builder. 615 */ 616 public Builder keyStore(final KeyStore keyStore) { 617 618 this.ks = keyStore; 619 return this; 620 } 621 622 623 /** 624 * Builds a new Elliptic Curve JWK. 625 * 626 * @return The Elliptic Curve JWK. 627 * 628 * @throws IllegalStateException If the JWK parameters were 629 * inconsistently specified. 630 */ 631 public ECKey build() { 632 633 try { 634 if (d == null && priv == null) { 635 // Public key 636 return new ECKey(crv, x, y, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, ks); 637 } 638 639 if (priv != null) { 640 // PKCS#11 reference to private key 641 return new ECKey(crv, x, y, priv, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, ks); 642 } 643 644 // Public / private key pair with 'd' 645 return new ECKey(crv, x, y, d, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, ks); 646 647 } catch (IllegalArgumentException e) { 648 throw new IllegalStateException(e.getMessage(), e); 649 } 650 } 651 } 652 653 654 /** 655 * Returns the Base64URL encoding of the specified elliptic curve 'x', 656 * 'y' or 'd' coordinate, with leading zero padding up to the specified 657 * field size in bits. 658 * 659 * @param fieldSize The field size in bits. 660 * @param coordinate The elliptic curve coordinate. Must not be 661 * {@code null}. 662 * 663 * @return The Base64URL-encoded coordinate, with leading zero padding 664 * up to the curve's field size. 665 */ 666 public static Base64URL encodeCoordinate(final int fieldSize, final BigInteger coordinate) { 667 668 final byte[] notPadded = BigIntegerUtils.toBytesUnsigned(coordinate); 669 670 int bytesToOutput = (fieldSize + 7)/8; 671 672 if (notPadded.length >= bytesToOutput) { 673 // Greater-than check to prevent exception on malformed 674 // key below 675 return Base64URL.encode(notPadded); 676 } 677 678 final byte[] padded = new byte[bytesToOutput]; 679 680 System.arraycopy(notPadded, 0, padded, bytesToOutput - notPadded.length, notPadded.length); 681 682 return Base64URL.encode(padded); 683 } 684 685 686 /** 687 * The curve name. 688 */ 689 private final Curve crv; 690 691 692 /** 693 * The public 'x' EC coordinate. 694 */ 695 private final Base64URL x; 696 697 698 /** 699 * The public 'y' EC coordinate. 700 */ 701 private final Base64URL y; 702 703 704 /** 705 * The private 'd' EC coordinate. 706 */ 707 private final Base64URL d; 708 709 710 /** 711 * Private PKCS#11 key handle. 712 */ 713 private final PrivateKey privateKey; 714 715 716 /** 717 * Ensures the specified 'x' and 'y' public coordinates are on the 718 * given curve. 719 * 720 * @param crv The curve. Must not be {@code null}. 721 * @param x The public 'x' coordinate. Must not be {@code null}. 722 * @param y The public 'y' coordinate. Must not be {@code null}. 723 */ 724 private static void ensurePublicCoordinatesOnCurve(final Curve crv, final Base64URL x, final Base64URL y) { 725 726 if (! SUPPORTED_CURVES.contains(crv)) { 727 throw new IllegalArgumentException("Unknown / unsupported curve: " + crv); 728 } 729 730 if (! ECChecks.isPointOnCurve(x.decodeToBigInteger(), y.decodeToBigInteger(), crv.toECParameterSpec())) { 731 throw new IllegalArgumentException("Invalid EC JWK: The 'x' and 'y' public coordinates are not on the " + crv + " curve"); 732 } 733 } 734 735 736 /** 737 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 738 * specified parameters. 739 * 740 * @param crv The cryptographic curve. Must not be {@code null}. 741 * @param x The public 'x' coordinate for the elliptic curve 742 * point. It is represented as the Base64URL encoding of 743 * the coordinate's big endian representation. Must not 744 * be {@code null}. 745 * @param y The public 'y' coordinate for the elliptic curve 746 * point. It is represented as the Base64URL encoding of 747 * the coordinate's big endian representation. Must not 748 * be {@code null}. 749 * @param use The key use, {@code null} if not specified or if the 750 * key is intended for signing as well as encryption. 751 * @param ops The key operations, {@code null} if not specified. 752 * @param alg The intended JOSE algorithm for the key, {@code null} 753 * if not specified. 754 * @param kid The key ID, {@code null} if not specified. 755 * @param x5u The X.509 certificate URL, {@code null} if not 756 * specified. 757 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 758 * if not specified. 759 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 760 * if not specified. 761 * @param x5c The X.509 certificate chain, {@code null} if not 762 * specified. 763 * @param ks Reference to the underlying key store, {@code null} if 764 * not specified. 765 */ 766 @Deprecated 767 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, 768 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 769 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 770 final KeyStore ks) { 771 772 this(crv, x, y, use, ops, alg, kid, x5u, x5t, x5t256, x5c, null, null, null, ks); 773 } 774 775 776 /** 777 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 778 * with the specified parameters. 779 * 780 * @param crv The cryptographic curve. Must not be {@code null}. 781 * @param x The public 'x' coordinate for the elliptic curve 782 * point. It is represented as the Base64URL encoding of 783 * the coordinate's big endian representation. Must not 784 * be {@code null}. 785 * @param y The public 'y' coordinate for the elliptic curve 786 * point. It is represented as the Base64URL encoding of 787 * the coordinate's big endian representation. Must not 788 * be {@code null}. 789 * @param d The private 'd' coordinate for the elliptic curve 790 * point. It is represented as the Base64URL encoding of 791 * the coordinate's big endian representation. Must not 792 * be {@code null}. 793 * @param use The key use, {@code null} if not specified or if the 794 * key is intended for signing as well as encryption. 795 * @param ops The key operations, {@code null} if not specified. 796 * @param alg The intended JOSE algorithm for the key, {@code null} 797 * if not specified. 798 * @param kid The key ID, {@code null} if not specified. 799 * @param x5u The X.509 certificate URL, {@code null} if not 800 * specified. 801 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 802 * if not specified. 803 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 804 * if not specified. 805 * @param x5c The X.509 certificate chain, {@code null} if not 806 * specified. 807 * @param ks Reference to the underlying key store, {@code null} if 808 * not specified. 809 */ 810 @Deprecated 811 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, final Base64URL d, 812 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 813 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 814 final KeyStore ks) { 815 816 this(crv, x, y, d, use, ops, alg, kid, x5u, x5t, x5t256, x5c, null, null, null, ks); 817 } 818 819 820 /** 821 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 822 * with the specified parameters. The private key is specified by its 823 * PKCS#11 handle. 824 * 825 * @param crv The cryptographic curve. Must not be {@code null}. 826 * @param x The public 'x' coordinate for the elliptic curve 827 * point. It is represented as the Base64URL encoding of 828 * the coordinate's big endian representation. Must not 829 * be {@code null}. 830 * @param y The public 'y' coordinate for the elliptic curve 831 * point. It is represented as the Base64URL encoding of 832 * the coordinate's big endian representation. Must not 833 * be {@code null}. 834 * @param priv The private key as a PKCS#11 handle, {@code null} if 835 * not specified. 836 * @param use The key use, {@code null} if not specified or if the 837 * key is intended for signing as well as encryption. 838 * @param ops The key operations, {@code null} if not specified. 839 * @param alg The intended JOSE algorithm for the key, {@code null} 840 * if not specified. 841 * @param kid The key ID, {@code null} if not specified. 842 * @param x5u The X.509 certificate URL, {@code null} if not 843 * specified. 844 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 845 * if not specified. 846 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 847 * if not specified. 848 * @param x5c The X.509 certificate chain, {@code null} if not 849 * specified. 850 */ 851 @Deprecated 852 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, final PrivateKey priv, 853 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 854 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 855 final KeyStore ks) { 856 857 this(crv, x, y, priv, use, ops, alg, kid, x5u, x5t, x5t256, x5c, null, null, null, ks); 858 } 859 860 861 /** 862 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 863 * specified parameters. 864 * 865 * @param crv The cryptographic curve. Must not be {@code null}. 866 * @param pub The public EC key to represent. Must not be 867 * {@code null}. 868 * @param use The key use, {@code null} if not specified or if the 869 * key is intended for signing as well as encryption. 870 * @param ops The key operations, {@code null} if not specified. 871 * @param alg The intended JOSE algorithm for the key, {@code null} 872 * if not specified. 873 * @param kid The key ID, {@code null} if not specified. 874 * @param x5u The X.509 certificate URL, {@code null} if not 875 * specified. 876 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 877 * if not specified. 878 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 879 * if not specified. 880 * @param x5c The X.509 certificate chain, {@code null} if not 881 * specified. 882 * @param ks Reference to the underlying key store, {@code null} if 883 * not specified. 884 */ 885 @Deprecated 886 public ECKey(final Curve crv, final ECPublicKey pub, 887 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 888 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 889 final KeyStore ks) { 890 891 this(crv, 892 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 893 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 894 use, ops, alg, kid, 895 x5u, x5t, x5t256, x5c, 896 null, null, null, 897 ks); 898 } 899 900 901 /** 902 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 903 * with the specified parameters. 904 * 905 * @param crv The cryptographic curve. Must not be {@code null}. 906 * @param pub The public EC key to represent. Must not be 907 * {@code null}. 908 * @param priv The private EC key to represent. Must not be 909 * {@code null}. 910 * @param use The key use, {@code null} if not specified or if the 911 * key is intended for signing as well as encryption. 912 * @param ops The key operations, {@code null} if not specified. 913 * @param alg The intended JOSE algorithm for the key, {@code null} 914 * if not specified. 915 * @param kid The key ID, {@code null} if not specified. 916 * @param x5u The X.509 certificate URL, {@code null} if not 917 * specified. 918 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 919 * if not specified. 920 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 921 * if not specified. 922 * @param x5c The X.509 certificate chain, {@code null} if not 923 * specified. 924 * @param ks Reference to the underlying key store, {@code null} if 925 * not specified. 926 */ 927 @Deprecated 928 public ECKey(final Curve crv, final ECPublicKey pub, final ECPrivateKey priv, 929 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 930 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 931 final KeyStore ks) { 932 933 this(crv, 934 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 935 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 936 encodeCoordinate(priv.getParams().getCurve().getField().getFieldSize(), priv.getS()), 937 use, ops, alg, kid, 938 x5u, x5t, x5t256, x5c, 939 null, null, null, 940 ks); 941 } 942 943 944 /** 945 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 946 * with the specified parameters. The private key is specified by its 947 * PKCS#11 handle. 948 * 949 * @param crv The cryptographic curve. Must not be {@code null}. 950 * @param pub The public EC key to represent. Must not be 951 * {@code null}. 952 * @param priv The private key as a PKCS#11 handle, {@code null} if 953 * not specified. 954 * @param use The key use, {@code null} if not specified or if the 955 * key is intended for signing as well as encryption. 956 * @param ops The key operations, {@code null} if not specified. 957 * @param alg The intended JOSE algorithm for the key, {@code null} 958 * if not specified. 959 * @param kid The key ID, {@code null} if not specified. 960 * @param x5u The X.509 certificate URL, {@code null} if not 961 * specified. 962 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 963 * if not specified. 964 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 965 * if not specified. 966 * @param x5c The X.509 certificate chain, {@code null} if not 967 * specified. 968 * @param ks Reference to the underlying key store, {@code null} if 969 * not specified. 970 */ 971 @Deprecated 972 public ECKey(final Curve crv, final ECPublicKey pub, final PrivateKey priv, 973 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 974 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 975 final KeyStore ks) { 976 977 this( 978 crv, 979 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 980 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 981 priv, 982 use, ops, alg, kid, x5u, x5t, x5t256, x5c, 983 null, null, null, 984 ks); 985 } 986 987 988 /** 989 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 990 * specified parameters. 991 * 992 * @param crv The cryptographic curve. Must not be {@code null}. 993 * @param x The public 'x' coordinate for the elliptic curve 994 * point. It is represented as the Base64URL encoding of 995 * the coordinate's big endian representation. Must not 996 * be {@code null}. 997 * @param y The public 'y' coordinate for the elliptic curve 998 * point. It is represented as the Base64URL encoding of 999 * the coordinate's big endian representation. Must not 1000 * be {@code null}. 1001 * @param use The key use, {@code null} if not specified or if the 1002 * key is intended for signing as well as encryption. 1003 * @param ops The key operations, {@code null} if not specified. 1004 * @param alg The intended JOSE algorithm for the key, {@code null} 1005 * if not specified. 1006 * @param kid The key ID, {@code null} if not specified. 1007 * @param x5u The X.509 certificate URL, {@code null} if not 1008 * specified. 1009 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 1010 * if not specified. 1011 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 1012 * if not specified. 1013 * @param x5c The X.509 certificate chain, {@code null} if not 1014 * specified. 1015 * @param exp The key expiration time, {@code null} if not 1016 * specified. 1017 * @param nbf The key not-before time, {@code null} if not 1018 * specified. 1019 * @param iat The key issued-at time, {@code null} if not specified. 1020 * @param ks Reference to the underlying key store, {@code null} if 1021 * not specified. 1022 */ 1023 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, 1024 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 1025 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 1026 final Date exp, final Date nbf, final Date iat, 1027 final KeyStore ks) { 1028 1029 super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, ks); 1030 1031 if (crv == null) { 1032 throw new IllegalArgumentException("The curve must not be null"); 1033 } 1034 1035 this.crv = crv; 1036 1037 if (x == null) { 1038 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 1039 } 1040 1041 this.x = x; 1042 1043 if (y == null) { 1044 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 1045 } 1046 1047 this.y = y; 1048 1049 ensurePublicCoordinatesOnCurve(crv, x, y); 1050 1051 ensureMatches(getParsedX509CertChain()); 1052 1053 this.d = null; 1054 1055 this.privateKey = null; 1056 } 1057 1058 1059 /** 1060 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 1061 * with the specified parameters. 1062 * 1063 * @param crv The cryptographic curve. Must not be {@code null}. 1064 * @param x The public 'x' coordinate for the elliptic curve 1065 * point. It is represented as the Base64URL encoding of 1066 * the coordinate's big endian representation. Must not 1067 * be {@code null}. 1068 * @param y The public 'y' coordinate for the elliptic curve 1069 * point. It is represented as the Base64URL encoding of 1070 * the coordinate's big endian representation. Must not 1071 * be {@code null}. 1072 * @param d The private 'd' coordinate for the elliptic curve 1073 * point. It is represented as the Base64URL encoding of 1074 * the coordinate's big endian representation. Must not 1075 * be {@code null}. 1076 * @param use The key use, {@code null} if not specified or if the 1077 * key is intended for signing as well as encryption. 1078 * @param ops The key operations, {@code null} if not specified. 1079 * @param alg The intended JOSE algorithm for the key, {@code null} 1080 * if not specified. 1081 * @param kid The key ID, {@code null} if not specified. 1082 * @param x5u The X.509 certificate URL, {@code null} if not 1083 * specified. 1084 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 1085 * if not specified. 1086 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 1087 * if not specified. 1088 * @param x5c The X.509 certificate chain, {@code null} if not 1089 * specified. 1090 * @param exp The key expiration time, {@code null} if not 1091 * specified. 1092 * @param nbf The key not-before time, {@code null} if not 1093 * specified. 1094 * @param iat The key issued-at time, {@code null} if not specified. 1095 * @param ks Reference to the underlying key store, {@code null} if 1096 * not specified. 1097 */ 1098 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, final Base64URL d, 1099 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 1100 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 1101 final Date exp, final Date nbf, final Date iat, 1102 final KeyStore ks) { 1103 1104 super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, ks); 1105 1106 if (crv == null) { 1107 throw new IllegalArgumentException("The curve must not be null"); 1108 } 1109 1110 this.crv = crv; 1111 1112 if (x == null) { 1113 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 1114 } 1115 1116 this.x = x; 1117 1118 if (y == null) { 1119 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 1120 } 1121 1122 this.y = y; 1123 1124 ensurePublicCoordinatesOnCurve(crv, x, y); 1125 1126 ensureMatches(getParsedX509CertChain()); 1127 1128 if (d == null) { 1129 throw new IllegalArgumentException("The 'd' coordinate must not be null"); 1130 } 1131 1132 this.d = d; 1133 1134 this.privateKey = null; 1135 } 1136 1137 1138 /** 1139 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 1140 * with the specified parameters. The private key is specified by its 1141 * PKCS#11 handle. 1142 * 1143 * @param crv The cryptographic curve. Must not be {@code null}. 1144 * @param x The public 'x' coordinate for the elliptic curve 1145 * point. It is represented as the Base64URL encoding of 1146 * the coordinate's big endian representation. Must not 1147 * be {@code null}. 1148 * @param y The public 'y' coordinate for the elliptic curve 1149 * point. It is represented as the Base64URL encoding of 1150 * the coordinate's big endian representation. Must not 1151 * be {@code null}. 1152 * @param priv The private key as a PKCS#11 handle, {@code null} if 1153 * not specified. 1154 * @param use The key use, {@code null} if not specified or if the 1155 * key is intended for signing as well as encryption. 1156 * @param ops The key operations, {@code null} if not specified. 1157 * @param alg The intended JOSE algorithm for the key, {@code null} 1158 * if not specified. 1159 * @param kid The key ID, {@code null} if not specified. 1160 * @param x5u The X.509 certificate URL, {@code null} if not 1161 * specified. 1162 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 1163 * if not specified. 1164 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 1165 * if not specified. 1166 * @param x5c The X.509 certificate chain, {@code null} if not 1167 * specified. 1168 * @param exp The key expiration time, {@code null} if not 1169 * specified. 1170 * @param nbf The key not-before time, {@code null} if not 1171 * specified. 1172 * @param iat The key issued-at time, {@code null} if not specified. 1173 * @param ks Reference to the underlying key store, {@code null} if 1174 * not specified. 1175 */ 1176 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, final PrivateKey priv, 1177 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 1178 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 1179 final Date exp, final Date nbf, final Date iat, 1180 final KeyStore ks) { 1181 1182 super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, ks); 1183 1184 if (crv == null) { 1185 throw new IllegalArgumentException("The curve must not be null"); 1186 } 1187 1188 this.crv = crv; 1189 1190 if (x == null) { 1191 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 1192 } 1193 1194 this.x = x; 1195 1196 if (y == null) { 1197 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 1198 } 1199 1200 this.y = y; 1201 1202 ensurePublicCoordinatesOnCurve(crv, x, y); 1203 1204 ensureMatches(getParsedX509CertChain()); 1205 1206 d = null; 1207 1208 this.privateKey = priv; 1209 } 1210 1211 1212 /** 1213 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 1214 * specified parameters. 1215 * 1216 * @param crv The cryptographic curve. Must not be {@code null}. 1217 * @param pub The public EC key to represent. Must not be 1218 * {@code null}. 1219 * @param use The key use, {@code null} if not specified or if the 1220 * key is intended for signing as well as encryption. 1221 * @param ops The key operations, {@code null} if not specified. 1222 * @param alg The intended JOSE algorithm for the key, {@code null} 1223 * if not specified. 1224 * @param kid The key ID, {@code null} if not specified. 1225 * @param x5u The X.509 certificate URL, {@code null} if not 1226 * specified. 1227 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 1228 * if not specified. 1229 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 1230 * if not specified. 1231 * @param x5c The X.509 certificate chain, {@code null} if not 1232 * specified. 1233 * @param exp The key expiration time, {@code null} if not 1234 * specified. 1235 * @param nbf The key not-before time, {@code null} if not 1236 * specified. 1237 * @param iat The key issued-at time, {@code null} if not specified. 1238 * @param ks Reference to the underlying key store, {@code null} if 1239 * not specified. 1240 */ 1241 public ECKey(final Curve crv, final ECPublicKey pub, 1242 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 1243 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 1244 final Date exp, final Date nbf, final Date iat, 1245 final KeyStore ks) { 1246 1247 this(crv, 1248 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 1249 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 1250 use, ops, alg, kid, 1251 x5u, x5t, x5t256, x5c, 1252 exp, nbf, iat, 1253 ks); 1254 } 1255 1256 1257 /** 1258 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 1259 * with the specified parameters. 1260 * 1261 * @param crv The cryptographic curve. Must not be {@code null}. 1262 * @param pub The public EC key to represent. Must not be 1263 * {@code null}. 1264 * @param priv The private EC key to represent. Must not be 1265 * {@code null}. 1266 * @param use The key use, {@code null} if not specified or if the 1267 * key is intended for signing as well as encryption. 1268 * @param ops The key operations, {@code null} if not specified. 1269 * @param alg The intended JOSE algorithm for the key, {@code null} 1270 * if not specified. 1271 * @param kid The key ID, {@code null} if not specified. 1272 * @param x5u The X.509 certificate URL, {@code null} if not 1273 * specified. 1274 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 1275 * if not specified. 1276 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 1277 * if not specified. 1278 * @param x5c The X.509 certificate chain, {@code null} if not 1279 * specified. 1280 * @param exp The key expiration time, {@code null} if not 1281 * specified. 1282 * @param nbf The key not-before time, {@code null} if not 1283 * specified. 1284 * @param iat The key issued-at time, {@code null} if not specified. 1285 * @param ks Reference to the underlying key store, {@code null} if 1286 * not specified. 1287 */ 1288 public ECKey(final Curve crv, final ECPublicKey pub, final ECPrivateKey priv, 1289 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 1290 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 1291 final Date exp, final Date nbf, final Date iat, 1292 final KeyStore ks) { 1293 1294 this(crv, 1295 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 1296 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 1297 encodeCoordinate(priv.getParams().getCurve().getField().getFieldSize(), priv.getS()), 1298 use, ops, alg, kid, 1299 x5u, x5t, x5t256, x5c, 1300 exp, nbf, iat, 1301 ks); 1302 } 1303 1304 1305 /** 1306 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 1307 * with the specified parameters. The private key is specified by its 1308 * PKCS#11 handle. 1309 * 1310 * @param crv The cryptographic curve. Must not be {@code null}. 1311 * @param pub The public EC key to represent. Must not be 1312 * {@code null}. 1313 * @param priv The private key as a PKCS#11 handle, {@code null} if 1314 * not specified. 1315 * @param use The key use, {@code null} if not specified or if the 1316 * key is intended for signing as well as encryption. 1317 * @param ops The key operations, {@code null} if not specified. 1318 * @param alg The intended JOSE algorithm for the key, {@code null} 1319 * if not specified. 1320 * @param kid The key ID, {@code null} if not specified. 1321 * @param x5u The X.509 certificate URL, {@code null} if not 1322 * specified. 1323 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 1324 * if not specified. 1325 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 1326 * if not specified. 1327 * @param x5c The X.509 certificate chain, {@code null} if not 1328 * specified. 1329 * @param exp The key expiration time, {@code null} if not 1330 * specified. 1331 * @param nbf The key not-before time, {@code null} if not 1332 * specified. 1333 * @param iat The key issued-at time, {@code null} if not specified. 1334 * @param ks Reference to the underlying key store, {@code null} if 1335 * not specified. 1336 */ 1337 public ECKey(final Curve crv, final ECPublicKey pub, final PrivateKey priv, 1338 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 1339 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 1340 final Date exp, final Date nbf, final Date iat, 1341 final KeyStore ks) { 1342 1343 this( 1344 crv, 1345 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 1346 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 1347 priv, 1348 use, ops, alg, kid, x5u, x5t, x5t256, x5c, 1349 exp, nbf, iat, 1350 ks); 1351 } 1352 1353 1354 @Override 1355 public Curve getCurve() { 1356 1357 return crv; 1358 } 1359 1360 1361 /** 1362 * Gets the public 'x' coordinate for the elliptic curve point. 1363 * 1364 * @return The 'x' coordinate. It is represented as the Base64URL 1365 * encoding of the coordinate's big endian representation. 1366 */ 1367 public Base64URL getX() { 1368 1369 return x; 1370 } 1371 1372 1373 /** 1374 * Gets the public 'y' coordinate for the elliptic curve point. 1375 * 1376 * @return The 'y' coordinate. It is represented as the Base64URL 1377 * encoding of the coordinate's big endian representation. 1378 */ 1379 public Base64URL getY() { 1380 1381 return y; 1382 } 1383 1384 1385 /** 1386 * Gets the private 'd' coordinate for the elliptic curve point. It is 1387 * represented as the Base64URL encoding of the coordinate's big endian 1388 * representation. 1389 * 1390 * @return The 'd' coordinate. It is represented as the Base64URL 1391 * encoding of the coordinate's big endian representation. 1392 * {@code null} if not specified (for a public key). 1393 */ 1394 public Base64URL getD() { 1395 1396 return d; 1397 } 1398 1399 1400 /** 1401 * Returns a standard {@code java.security.interfaces.ECPublicKey} 1402 * representation of this Elliptic Curve JWK. Uses the default JCA 1403 * provider. 1404 * 1405 * @return The public Elliptic Curve key. 1406 * 1407 * @throws JOSEException If EC is not supported by the underlying Java 1408 * Cryptography (JCA) provider or if the JWK 1409 * parameters are invalid for a public EC key. 1410 */ 1411 public ECPublicKey toECPublicKey() 1412 throws JOSEException { 1413 1414 return toECPublicKey(null); 1415 } 1416 1417 1418 /** 1419 * Returns a standard {@code java.security.interfaces.ECPublicKey} 1420 * representation of this Elliptic Curve JWK. 1421 * 1422 * @param provider The specific JCA provider to use, {@code null} 1423 * implies the default one. 1424 * 1425 * @return The public Elliptic Curve key. 1426 * 1427 * @throws JOSEException If EC is not supported by the underlying Java 1428 * Cryptography (JCA) provider or if the JWK 1429 * parameters are invalid for a public EC key. 1430 */ 1431 public ECPublicKey toECPublicKey(final Provider provider) 1432 throws JOSEException { 1433 1434 ECParameterSpec spec = crv.toECParameterSpec(); 1435 1436 if (spec == null) { 1437 throw new JOSEException("Couldn't get EC parameter spec for curve " + crv); 1438 } 1439 1440 ECPoint w = new ECPoint(x.decodeToBigInteger(), y.decodeToBigInteger()); 1441 1442 ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(w, spec); 1443 1444 try { 1445 KeyFactory keyFactory; 1446 1447 if (provider == null) { 1448 keyFactory = KeyFactory.getInstance("EC"); 1449 } else { 1450 keyFactory = KeyFactory.getInstance("EC", provider); 1451 } 1452 1453 return (ECPublicKey) keyFactory.generatePublic(publicKeySpec); 1454 1455 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 1456 1457 throw new JOSEException(e.getMessage(), e); 1458 } 1459 } 1460 1461 1462 /** 1463 * Returns a standard {@code java.security.interfaces.ECPrivateKey} 1464 * representation of this Elliptic Curve JWK. Uses the default JCA 1465 * provider. 1466 * 1467 * @return The private Elliptic Curve key, {@code null} if not 1468 * specified by this JWK. 1469 * 1470 * @throws JOSEException If EC is not supported by the underlying Java 1471 * Cryptography (JCA) provider or if the JWK 1472 * parameters are invalid for a private EC key. 1473 */ 1474 public ECPrivateKey toECPrivateKey() 1475 throws JOSEException { 1476 1477 return toECPrivateKey(null); 1478 } 1479 1480 1481 /** 1482 * Returns a standard {@code java.security.interfaces.ECPrivateKey} 1483 * representation of this Elliptic Curve JWK. 1484 * 1485 * @param provider The specific JCA provider to use, {@code null} 1486 * implies the default one. 1487 * 1488 * @return The private Elliptic Curve key, {@code null} if not 1489 * specified by this JWK. 1490 * 1491 * @throws JOSEException If EC is not supported by the underlying Java 1492 * Cryptography (JCA) provider or if the JWK 1493 * parameters are invalid for a private EC key. 1494 */ 1495 public ECPrivateKey toECPrivateKey(final Provider provider) 1496 throws JOSEException { 1497 1498 if (d == null) { 1499 // No private 'd' param 1500 return null; 1501 } 1502 1503 ECParameterSpec spec = crv.toECParameterSpec(); 1504 1505 if (spec == null) { 1506 throw new JOSEException("Couldn't get EC parameter spec for curve " + crv); 1507 } 1508 1509 ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(d.decodeToBigInteger(), spec); 1510 1511 try { 1512 KeyFactory keyFactory; 1513 1514 if (provider == null) { 1515 keyFactory = KeyFactory.getInstance("EC"); 1516 } else { 1517 keyFactory = KeyFactory.getInstance("EC", provider); 1518 } 1519 1520 return (ECPrivateKey) keyFactory.generatePrivate(privateKeySpec); 1521 1522 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 1523 1524 throw new JOSEException(e.getMessage(), e); 1525 } 1526 } 1527 1528 1529 @Override 1530 public PublicKey toPublicKey() 1531 throws JOSEException { 1532 1533 return toECPublicKey(); 1534 } 1535 1536 1537 @Override 1538 public PrivateKey toPrivateKey() 1539 throws JOSEException { 1540 1541 PrivateKey prv = toECPrivateKey(); 1542 1543 if (prv != null) { 1544 // Return private EC key with key material 1545 return prv; 1546 } 1547 1548 // Return private EC key as PKCS#11 handle, or null 1549 return privateKey; 1550 } 1551 1552 1553 /** 1554 * Returns a standard {@code java.security.KeyPair} representation of 1555 * this Elliptic Curve JWK. Uses the default JCA provider. 1556 * 1557 * @return The Elliptic Curve key pair. The private Elliptic Curve key 1558 * will be {@code null} if not specified. 1559 * 1560 * @throws JOSEException If EC is not supported by the underlying Java 1561 * Cryptography (JCA) provider or if the JWK 1562 * parameters are invalid for a public and / or 1563 * private EC key. 1564 */ 1565 @Override 1566 public KeyPair toKeyPair() 1567 throws JOSEException { 1568 1569 return toKeyPair(null); 1570 } 1571 1572 1573 /** 1574 * Returns a standard {@code java.security.KeyPair} representation of 1575 * this Elliptic Curve JWK. 1576 * 1577 * @param provider The specific JCA provider to use, {@code null} 1578 * implies the default one. 1579 * 1580 * @return The Elliptic Curve key pair. The private Elliptic Curve key 1581 * will be {@code null} if not specified. 1582 * 1583 * @throws JOSEException If EC is not supported by the underlying Java 1584 * Cryptography (JCA) provider or if the JWK 1585 * parameters are invalid for a public and / or 1586 * private EC key. 1587 */ 1588 public KeyPair toKeyPair(final Provider provider) 1589 throws JOSEException { 1590 1591 if (privateKey != null) { 1592 // Private key as PKCS#11 handle 1593 return new KeyPair(toECPublicKey(provider), privateKey); 1594 } else { 1595 return new KeyPair(toECPublicKey(provider), toECPrivateKey(provider)); 1596 } 1597 } 1598 1599 1600 @Override 1601 public boolean matches(final X509Certificate cert) { 1602 1603 ECPublicKey certECKey; 1604 try { 1605 certECKey = (ECPublicKey) getParsedX509CertChain().get(0).getPublicKey(); 1606 } catch (ClassCastException ex) { 1607 return false; 1608 } 1609 // Compare Big Ints, base64url encoding may have padding! 1610 // https://tools.ietf.org/html/rfc7518#section-6.2.1.2 1611 if (! getX().decodeToBigInteger().equals(certECKey.getW().getAffineX())) { 1612 return false; 1613 } 1614 return getY().decodeToBigInteger().equals(certECKey.getW().getAffineY()); 1615 } 1616 1617 1618 /** 1619 * Calls {@link #matches(X509Certificate)} for the first X.509 1620 * certificate in the specified chain. 1621 * 1622 * @param chain The X.509 certificate chain, {@code null} if not 1623 * specified. 1624 * 1625 * @throws IllegalArgumentException If a certificate chain is specified 1626 * and the first certificate in it 1627 * doesn't match. 1628 */ 1629 private void ensureMatches(final List<X509Certificate> chain) { 1630 1631 if (chain == null) 1632 return; 1633 1634 if (! matches(chain.get(0))) 1635 throw new IllegalArgumentException("The public subject key info of the first X.509 certificate in the chain must match the JWK type and public parameters"); 1636 } 1637 1638 1639 @Override 1640 public LinkedHashMap<String,?> getRequiredParams() { 1641 1642 // Put mandatory params in sorted order 1643 LinkedHashMap<String,String> requiredParams = new LinkedHashMap<>(); 1644 requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE, crv.toString()); 1645 requiredParams.put(JWKParameterNames.KEY_TYPE, getKeyType().getValue()); 1646 requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE_X_COORDINATE, x.toString()); 1647 requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE_Y_COORDINATE, y.toString()); 1648 return requiredParams; 1649 } 1650 1651 1652 @Override 1653 public boolean isPrivate() { 1654 1655 return d != null || privateKey != null; 1656 } 1657 1658 1659 @Override 1660 public int size() { 1661 1662 ECParameterSpec ecParameterSpec = crv.toECParameterSpec(); 1663 1664 if (ecParameterSpec == null) { 1665 throw new UnsupportedOperationException("Couldn't determine field size for curve " + crv.getName()); 1666 } 1667 1668 return ecParameterSpec.getCurve().getField().getFieldSize(); 1669 } 1670 1671 1672 /** 1673 * Returns a copy of this Elliptic Curve JWK with any private values 1674 * removed. 1675 * 1676 * @return The copied public Elliptic Curve JWK. 1677 */ 1678 @Override 1679 public ECKey toPublicJWK() { 1680 1681 return new ECKey( 1682 getCurve(), getX(), getY(), 1683 getKeyUse(), getKeyOperations(), getAlgorithm(), getKeyID(), 1684 getX509CertURL(), getX509CertThumbprint(), getX509CertSHA256Thumbprint(), getX509CertChain(), 1685 getExpirationTime(), getNotBeforeTime(), getIssueTime(), 1686 getKeyStore()); 1687 } 1688 1689 1690 @Override 1691 public Map<String, Object> toJSONObject() { 1692 1693 Map<String, Object> o = super.toJSONObject(); 1694 1695 // Append EC specific attributes 1696 o.put(JWKParameterNames.ELLIPTIC_CURVE, crv.toString()); 1697 o.put(JWKParameterNames.ELLIPTIC_CURVE_X_COORDINATE, x.toString()); 1698 o.put(JWKParameterNames.ELLIPTIC_CURVE_Y_COORDINATE, y.toString()); 1699 1700 if (d != null) { 1701 o.put(JWKParameterNames.ELLIPTIC_CURVE_PRIVATE_KEY, d.toString()); 1702 } 1703 1704 return o; 1705 } 1706 1707 1708 /** 1709 * Parses a public / private Elliptic Curve JWK from the specified JSON 1710 * object string representation. 1711 * 1712 * @param s The JSON object string to parse. Must not be {@code null}. 1713 * 1714 * @return The public / private Elliptic Curve JWK. 1715 * 1716 * @throws ParseException If the string couldn't be parsed to an 1717 * Elliptic Curve JWK. 1718 */ 1719 public static ECKey parse(final String s) 1720 throws ParseException { 1721 1722 return parse(JSONObjectUtils.parse(s)); 1723 } 1724 1725 1726 /** 1727 * Parses a public / private Elliptic Curve JWK from the specified JSON 1728 * object representation. 1729 * 1730 * @param jsonObject The JSON object to parse. Must not be 1731 * {@code null}. 1732 * 1733 * @return The public / private Elliptic Curve JWK. 1734 * 1735 * @throws ParseException If the JSON object couldn't be parsed to an 1736 * Elliptic Curve JWK. 1737 */ 1738 public static ECKey parse(final Map<String, Object> jsonObject) 1739 throws ParseException { 1740 1741 // Check key type 1742 if (! KeyType.EC.equals(JWKMetadata.parseKeyType(jsonObject))) { 1743 throw new ParseException("The key type \"kty\" must be EC", 0); 1744 } 1745 1746 // Parse the mandatory public key parameters 1747 Curve crv; 1748 try { 1749 crv = Curve.parse(JSONObjectUtils.getString(jsonObject, JWKParameterNames.ELLIPTIC_CURVE)); 1750 } catch (IllegalArgumentException e) { 1751 throw new ParseException(e.getMessage(), 0); 1752 } 1753 1754 Base64URL x = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.ELLIPTIC_CURVE_X_COORDINATE); 1755 Base64URL y = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.ELLIPTIC_CURVE_Y_COORDINATE); 1756 1757 // Get optional private key 1758 Base64URL d = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.ELLIPTIC_CURVE_PRIVATE_KEY); 1759 1760 try { 1761 if (d == null) { 1762 // Public key 1763 return new ECKey(crv, x, y, 1764 JWKMetadata.parseKeyUse(jsonObject), 1765 JWKMetadata.parseKeyOperations(jsonObject), 1766 JWKMetadata.parseAlgorithm(jsonObject), 1767 JWKMetadata.parseKeyID(jsonObject), 1768 JWKMetadata.parseX509CertURL(jsonObject), 1769 JWKMetadata.parseX509CertThumbprint(jsonObject), 1770 JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject), 1771 JWKMetadata.parseX509CertChain(jsonObject), 1772 JWKMetadata.parseExpirationTime(jsonObject), 1773 JWKMetadata.parseNotBeforeTime(jsonObject), 1774 JWKMetadata.parseIssueTime(jsonObject), 1775 null); 1776 1777 } else { 1778 // Key pair 1779 return new ECKey(crv, x, y, d, 1780 JWKMetadata.parseKeyUse(jsonObject), 1781 JWKMetadata.parseKeyOperations(jsonObject), 1782 JWKMetadata.parseAlgorithm(jsonObject), 1783 JWKMetadata.parseKeyID(jsonObject), 1784 JWKMetadata.parseX509CertURL(jsonObject), 1785 JWKMetadata.parseX509CertThumbprint(jsonObject), 1786 JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject), 1787 JWKMetadata.parseX509CertChain(jsonObject), 1788 JWKMetadata.parseExpirationTime(jsonObject), 1789 JWKMetadata.parseNotBeforeTime(jsonObject), 1790 JWKMetadata.parseIssueTime(jsonObject), 1791 null); 1792 } 1793 1794 } catch (IllegalArgumentException ex) { 1795 1796 // Missing x or y, conflicting 'use' and 'key_ops' 1797 throw new ParseException(ex.getMessage(), 0); 1798 } 1799 } 1800 1801 1802 /** 1803 * Parses a public Elliptic Curve JWK from the specified X.509 1804 * certificate. Requires BouncyCastle. 1805 * 1806 * <p><strong>Important:</strong> The X.509 certificate is not 1807 * validated! 1808 * 1809 * <p>Sets the following JWK parameters: 1810 * 1811 * <ul> 1812 * <li>The curve is obtained from the subject public key info 1813 * algorithm parameters. 1814 * <li>The JWK use inferred by {@link KeyUse#from}. 1815 * <li>The JWK ID from the X.509 serial number (in base 10). 1816 * <li>The JWK X.509 certificate chain (this certificate only). 1817 * <li>The JWK X.509 certificate SHA-256 thumbprint. 1818 * </ul> 1819 * 1820 * @param cert The X.509 certificate. Must not be {@code null}. 1821 * 1822 * @return The public Elliptic Curve JWK. 1823 * 1824 * @throws JOSEException If parsing failed. 1825 */ 1826 public static ECKey parse(final X509Certificate cert) 1827 throws JOSEException { 1828 1829 if (! (cert.getPublicKey() instanceof ECPublicKey)) { 1830 throw new JOSEException("The public key of the X.509 certificate is not EC"); 1831 } 1832 1833 ECPublicKey publicKey = (ECPublicKey) cert.getPublicKey(); 1834 1835 try { 1836 JcaX509CertificateHolder certHolder = new JcaX509CertificateHolder(cert); 1837 1838 String oid = certHolder.getSubjectPublicKeyInfo().getAlgorithm().getParameters().toString(); 1839 1840 Curve crv = Curve.forOID(oid); 1841 1842 if (crv == null) { 1843 throw new JOSEException("Couldn't determine EC JWK curve for OID " + oid); 1844 } 1845 1846 MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); 1847 1848 return new ECKey.Builder(crv, publicKey) 1849 .keyUse(KeyUse.from(cert)) 1850 .keyID(cert.getSerialNumber().toString(10)) 1851 .x509CertChain(Collections.singletonList(Base64.encode(cert.getEncoded()))) 1852 .x509CertSHA256Thumbprint(Base64URL.encode(sha256.digest(cert.getEncoded()))) 1853 .expirationTime(cert.getNotAfter()) 1854 .notBeforeTime(cert.getNotBefore()) 1855 .build(); 1856 } catch (NoSuchAlgorithmException e) { 1857 throw new JOSEException("Couldn't encode x5t parameter: " + e.getMessage(), e); 1858 } catch (CertificateEncodingException e) { 1859 throw new JOSEException("Couldn't encode x5c parameter: " + e.getMessage(), e); 1860 } 1861 } 1862 1863 1864 /** 1865 * Loads a public / private Elliptic Curve JWK from the specified JCA 1866 * key store. Requires BouncyCastle. 1867 * 1868 * <p><strong>Important:</strong> The X.509 certificate is not 1869 * validated! 1870 * 1871 * @param keyStore The key store. Must not be {@code null}. 1872 * @param alias The alias. Must not be {@code null}. 1873 * @param pin The pin to unlock the private key if any, empty or 1874 * {@code null} if not required. 1875 * 1876 * @return The public / private Elliptic Curve JWK., {@code null} if no 1877 * key with the specified alias was found. 1878 * 1879 * @throws KeyStoreException On a key store exception. 1880 * @throws JOSEException If EC key loading failed. 1881 */ 1882 public static ECKey load(final KeyStore keyStore, 1883 final String alias, 1884 final char[] pin) 1885 throws KeyStoreException, JOSEException { 1886 1887 Certificate cert = keyStore.getCertificate(alias); 1888 1889 if (!(cert instanceof X509Certificate)) { 1890 return null; 1891 } 1892 1893 X509Certificate x509Cert = (X509Certificate)cert; 1894 1895 if (! (x509Cert.getPublicKey() instanceof ECPublicKey)) { 1896 throw new JOSEException("Couldn't load EC JWK: The key algorithm is not EC"); 1897 } 1898 1899 ECKey ecJWK = ECKey.parse(x509Cert); 1900 1901 // Let kid=alias 1902 ecJWK = new ECKey.Builder(ecJWK).keyID(alias).keyStore(keyStore).build(); 1903 1904 // Check for private counterpart 1905 Key key; 1906 try { 1907 key = keyStore.getKey(alias, pin); 1908 } catch (UnrecoverableKeyException | NoSuchAlgorithmException e) { 1909 throw new JOSEException("Couldn't retrieve private EC key (bad pin?): " + e.getMessage(), e); 1910 } 1911 1912 if (key instanceof ECPrivateKey) { 1913 // Simple file based key store 1914 return new ECKey.Builder(ecJWK) 1915 .privateKey((ECPrivateKey)key) 1916 .build(); 1917 } else if (key instanceof PrivateKey && "EC".equalsIgnoreCase(key.getAlgorithm())) { 1918 // PKCS#11 store 1919 return new ECKey.Builder(ecJWK) 1920 .privateKey((PrivateKey)key) 1921 .build(); 1922 } else { 1923 return ecJWK; 1924 } 1925 } 1926 1927 1928 @Override 1929 public boolean equals(Object o) { 1930 if (this == o) return true; 1931 if (!(o instanceof ECKey)) return false; 1932 if (!super.equals(o)) return false; 1933 ECKey ecKey = (ECKey) o; 1934 return Objects.equals(crv, ecKey.crv) && 1935 Objects.equals(x, ecKey.x) && 1936 Objects.equals(y, ecKey.y) && 1937 Objects.equals(d, ecKey.d) && 1938 Objects.equals(privateKey, ecKey.privateKey); 1939 } 1940 1941 1942 @Override 1943 public int hashCode() { 1944 return Objects.hash(super.hashCode(), crv, x, y, d, privateKey); 1945 } 1946}