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 com.nimbusds.jose.Algorithm; 034import com.nimbusds.jose.JOSEException; 035import com.nimbusds.jose.crypto.utils.ECChecks; 036import com.nimbusds.jose.util.Base64; 037import com.nimbusds.jose.util.Base64URL; 038import com.nimbusds.jose.util.BigIntegerUtils; 039import com.nimbusds.jose.util.JSONObjectUtils; 040import net.jcip.annotations.Immutable; 041import net.minidev.json.JSONObject; 042import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 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#P_384 P-384} 054 * <li>{@link Curve#P_521 P-512} 055 * </ul> 056 * 057 * <p>Provides EC JWK import from / export to the following standard Java 058 * interfaces and classes: 059 * 060 * <ul> 061 * <li>{@link java.security.interfaces.ECPublicKey} 062 * <li>{@link java.security.interfaces.ECPrivateKey} 063 * <li>{@link java.security.PrivateKey} for an EC key in a PKCS#11 store 064 * <li>{@link java.security.KeyPair} 065 * </ul> 066 * 067 * <p>Example JSON object representation of a public EC JWK: 068 * 069 * <pre> 070 * { 071 * "kty" : "EC", 072 * "crv" : "P-256", 073 * "x" : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", 074 * "y" : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", 075 * "use" : "enc", 076 * "kid" : "1" 077 * } 078 * </pre> 079 * 080 * <p>Example JSON object representation of a private EC JWK: 081 * 082 * <pre> 083 * { 084 * "kty" : "EC", 085 * "crv" : "P-256", 086 * "x" : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", 087 * "y" : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", 088 * "d" : "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE", 089 * "use" : "enc", 090 * "kid" : "1" 091 * } 092 * </pre> 093 * 094 * <p>Use the builder to create a new EC JWK: 095 * 096 * <pre> 097 * ECKey key = new ECKey.Builder(Curve.P_256, x, y) 098 * .keyUse(KeyUse.SIGNATURE) 099 * .keyID("1") 100 * .build(); 101 * </pre> 102 * 103 * <p>See http://en.wikipedia.org/wiki/Elliptic_curve_cryptography 104 * 105 * @author Vladimir Dzhuvinov 106 * @author Justin Richer 107 * @version 2018-08-25 108 */ 109@Immutable 110public final class ECKey extends JWK implements AssymetricJWK, CurveBasedJWK { 111 112 113 private static final long serialVersionUID = 1L; 114 115 116 /** 117 * Supported EC curves. 118 */ 119 public static final Set<Curve> SUPPORTED_CURVES = Collections.unmodifiableSet( 120 new HashSet<>(Arrays.asList(Curve.P_256, Curve.P_384, Curve.P_521)) 121 ); 122 123 124 /** 125 * Builder for constructing Elliptic Curve JWKs. 126 * 127 * <p>Example usage: 128 * 129 * <pre> 130 * ECKey key = new ECKey.Builder(Curve.P521, x, y) 131 * .d(d) 132 * .algorithm(JWSAlgorithm.ES512) 133 * .keyID("1") 134 * .build(); 135 * </pre> 136 */ 137 public static class Builder { 138 139 140 /** 141 * The curve name. 142 */ 143 private final Curve crv; 144 145 146 /** 147 * The public 'x' EC coordinate. 148 */ 149 private final Base64URL x; 150 151 152 /** 153 * The public 'y' EC coordinate. 154 */ 155 private final Base64URL y; 156 157 158 /** 159 * The private 'd' EC coordinate, optional. 160 */ 161 private Base64URL d; 162 163 164 /** 165 * The private EC key, as PKCS#11 handle, optional. 166 */ 167 private PrivateKey priv; 168 169 170 /** 171 * The key use, optional. 172 */ 173 private KeyUse use; 174 175 176 /** 177 * The key operations, optional. 178 */ 179 private Set<KeyOperation> ops; 180 181 182 /** 183 * The intended JOSE algorithm for the key, optional. 184 */ 185 private Algorithm alg; 186 187 188 /** 189 * The key ID, optional. 190 */ 191 private String kid; 192 193 194 /** 195 * X.509 certificate URL, optional. 196 */ 197 private URI x5u; 198 199 200 /** 201 * X.509 certificate SHA-1 thumbprint, optional. 202 */ 203 @Deprecated 204 private Base64URL x5t; 205 206 207 /** 208 * X.509 certificate SHA-256 thumbprint, optional. 209 */ 210 private Base64URL x5t256; 211 212 213 /** 214 * The X.509 certificate chain, optional. 215 */ 216 private List<Base64> x5c; 217 218 219 /** 220 * Reference to the underlying key store, {@code null} if none. 221 */ 222 private KeyStore ks; 223 224 225 /** 226 * Creates a new Elliptic Curve JWK builder. 227 * 228 * @param crv The cryptographic curve. Must not be 229 * {@code null}. 230 * @param x The public 'x' coordinate for the elliptic curve 231 * point. It is represented as the Base64URL 232 * encoding of the coordinate's big endian 233 * representation. Must not be {@code null}. 234 * @param y The public 'y' coordinate for the elliptic curve 235 * point. It is represented as the Base64URL 236 * encoding of the coordinate's big endian 237 * representation. Must not be {@code null}. 238 */ 239 public Builder(final Curve crv, final Base64URL x, final Base64URL y) { 240 241 if (crv == null) { 242 throw new IllegalArgumentException("The curve must not be null"); 243 } 244 245 this.crv = crv; 246 247 if (x == null) { 248 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 249 } 250 251 this.x = x; 252 253 if (y == null) { 254 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 255 } 256 257 this.y = y; 258 } 259 260 261 /** 262 * Creates a new Elliptic Curve JWK builder. 263 * 264 * @param crv The cryptographic curve. Must not be 265 * {@code null}. 266 * @param pub The public EC key to represent. Must not be 267 * {@code null}. 268 */ 269 public Builder(final Curve crv, final ECPublicKey pub) { 270 271 this(crv, 272 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 273 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY())); 274 } 275 276 277 /** 278 * Creates a new Elliptic Curve JWK builder. 279 * 280 * @param ecJWK The EC JWK to start with. Must not be 281 * {@code null}. 282 */ 283 public Builder(final ECKey ecJWK) { 284 285 crv = ecJWK.crv; 286 x = ecJWK.x; 287 y = ecJWK.y; 288 d = ecJWK.d; 289 priv = ecJWK.privateKey; 290 use = ecJWK.getKeyUse(); 291 ops = ecJWK.getKeyOperations(); 292 alg = ecJWK.getAlgorithm(); 293 kid = ecJWK.getKeyID(); 294 x5u = ecJWK.getX509CertURL(); 295 x5t = ecJWK.getX509CertThumbprint(); 296 x5t256 = ecJWK.getX509CertSHA256Thumbprint(); 297 x5c = ecJWK.getX509CertChain(); 298 ks = ecJWK.getKeyStore(); 299 } 300 301 302 /** 303 * Sets the private 'd' coordinate for the elliptic curve 304 * point. The alternative method is {@link #privateKey}. 305 * 306 * @param d The private 'd' coordinate. It is represented as 307 * the Base64URL encoding of the coordinate's big 308 * endian representation. {@code null} if not 309 * specified (for a public key). 310 * 311 * @return This builder. 312 */ 313 public Builder d(final Base64URL d) { 314 315 this.d = d; 316 return this; 317 } 318 319 320 /** 321 * Sets the private Elliptic Curve key. The alternative method 322 * is {@link #d}. 323 * 324 * @param priv The private EC key, used to obtain the private 325 * 'd' coordinate for the elliptic curve point. 326 * {@code null} if not specified (for a public 327 * key). 328 * 329 * @return This builder. 330 */ 331 public Builder privateKey(final ECPrivateKey priv) { 332 333 if (priv != null) { 334 this.d = encodeCoordinate(priv.getParams().getCurve().getField().getFieldSize(), priv.getS()); 335 } 336 337 return this; 338 } 339 340 341 /** 342 * Sets the private EC key, typically for a key located in a 343 * PKCS#11 store that doesn't expose the private key parameters 344 * (such as a smart card or HSM). 345 * 346 * @param priv The private EC key reference. Its algorithm must 347 * be "EC". Must not be {@code null}. 348 * 349 * @return This builder. 350 */ 351 public Builder privateKey(final PrivateKey priv) { 352 353 if (! "EC".equalsIgnoreCase(priv.getAlgorithm())) { 354 throw new IllegalArgumentException("The private key algorithm must be EC"); 355 } 356 357 this.priv = priv; 358 return this; 359 } 360 361 362 /** 363 * Sets the use ({@code use}) of the JWK. 364 * 365 * @param use The key use, {@code null} if not specified or if 366 * the key is intended for signing as well as 367 * encryption. 368 * 369 * @return This builder. 370 */ 371 public Builder keyUse(final KeyUse use) { 372 373 this.use = use; 374 return this; 375 } 376 377 378 /** 379 * Sets the operations ({@code key_ops}) of the JWK. 380 * 381 * @param ops The key operations, {@code null} if not 382 * specified. 383 * 384 * @return This builder. 385 */ 386 public Builder keyOperations(final Set<KeyOperation> ops) { 387 388 this.ops = ops; 389 return this; 390 } 391 392 393 /** 394 * Sets the intended JOSE algorithm ({@code alg}) for the JWK. 395 * 396 * @param alg The intended JOSE algorithm, {@code null} if not 397 * specified. 398 * 399 * @return This builder. 400 */ 401 public Builder algorithm(final Algorithm alg) { 402 403 this.alg = alg; 404 return this; 405 } 406 407 /** 408 * Sets the ID ({@code kid}) of the JWK. The key ID can be used 409 * to match a specific key. This can be used, for instance, to 410 * choose a key within a {@link JWKSet} during key rollover. 411 * The key ID may also correspond to a JWS/JWE {@code kid} 412 * header parameter value. 413 * 414 * @param kid The key ID, {@code null} if not specified. 415 * 416 * @return This builder. 417 */ 418 public Builder keyID(final String kid) { 419 420 this.kid = kid; 421 return this; 422 } 423 424 425 /** 426 * Sets the ID ({@code kid}) of the JWK to its SHA-256 JWK 427 * thumbprint (RFC 7638). The key ID can be used to match a 428 * specific key. This can be used, for instance, to choose a 429 * key within a {@link JWKSet} during key rollover. The key ID 430 * may also correspond to a JWS/JWE {@code kid} header 431 * parameter value. 432 * 433 * @return This builder. 434 * 435 * @throws JOSEException If the SHA-256 hash algorithm is not 436 * supported. 437 */ 438 public Builder keyIDFromThumbprint() 439 throws JOSEException { 440 441 return keyIDFromThumbprint("SHA-256"); 442 } 443 444 445 /** 446 * Sets the ID ({@code kid}) of the JWK to its JWK thumbprint 447 * (RFC 7638). The key ID can be used to match a specific key. 448 * This can be used, for instance, to choose a key within a 449 * {@link JWKSet} during key rollover. The key ID may also 450 * correspond to a JWS/JWE {@code kid} header parameter value. 451 * 452 * @param hashAlg The hash algorithm for the JWK thumbprint 453 * computation. Must not be {@code null}. 454 * 455 * @return This builder. 456 * 457 * @throws JOSEException If the hash algorithm is not 458 * supported. 459 */ 460 public Builder keyIDFromThumbprint(final String hashAlg) 461 throws JOSEException { 462 463 // Put mandatory params in sorted order 464 LinkedHashMap<String,String> requiredParams = new LinkedHashMap<>(); 465 requiredParams.put("crv", crv.toString()); 466 requiredParams.put("kty", KeyType.EC.getValue()); 467 requiredParams.put("x", x.toString()); 468 requiredParams.put("y", y.toString()); 469 this.kid = ThumbprintUtils.compute(hashAlg, requiredParams).toString(); 470 return this; 471 } 472 473 474 /** 475 * Sets the X.509 certificate URL ({@code x5u}) of the JWK. 476 * 477 * @param x5u The X.509 certificate URL, {@code null} if not 478 * specified. 479 * 480 * @return This builder. 481 */ 482 public Builder x509CertURL(final URI x5u) { 483 484 this.x5u = x5u; 485 return this; 486 } 487 488 489 /** 490 * Sets the X.509 certificate SHA-1 thumbprint ({@code x5t}) of 491 * the JWK. 492 * 493 * @param x5t The X.509 certificate SHA-1 thumbprint, 494 * {@code null} if not specified. 495 * 496 * @return This builder. 497 */ 498 @Deprecated 499 public Builder x509CertThumbprint(final Base64URL x5t) { 500 501 this.x5t = x5t; 502 return this; 503 } 504 505 506 /** 507 * Sets the X.509 certificate SHA-256 thumbprint 508 * ({@code x5t#S256}) of the JWK. 509 * 510 * @param x5t256 The X.509 certificate SHA-256 thumbprint, 511 * {@code null} if not specified. 512 * 513 * @return This builder. 514 */ 515 public Builder x509CertSHA256Thumbprint(final Base64URL x5t256) { 516 517 this.x5t256 = x5t256; 518 return this; 519 } 520 521 522 /** 523 * Sets the X.509 certificate chain ({@code x5c}) of the JWK. 524 * 525 * @param x5c The X.509 certificate chain as a unmodifiable 526 * list, {@code null} if not specified. 527 * 528 * @return This builder. 529 */ 530 public Builder x509CertChain(final List<Base64> x5c) { 531 532 this.x5c = x5c; 533 return this; 534 } 535 536 537 /** 538 * Sets the underlying key store. 539 * 540 * @param keyStore Reference to the underlying key store, 541 * {@code null} if none. 542 * 543 * @return This builder. 544 */ 545 public Builder keyStore(final KeyStore keyStore) { 546 547 this.ks = keyStore; 548 return this; 549 } 550 551 552 /** 553 * Builds a new Elliptic Curve JWK. 554 * 555 * @return The Elliptic Curve JWK. 556 * 557 * @throws IllegalStateException If the JWK parameters were 558 * inconsistently specified. 559 */ 560 public ECKey build() { 561 562 try { 563 if (d == null && priv == null) { 564 // Public key 565 return new ECKey(crv, x, y, use, ops, alg, kid, x5u, x5t, x5t256, x5c, ks); 566 } 567 568 if (priv != null) { 569 // PKCS#11 reference to private key 570 return new ECKey(crv, x, y, priv, use, ops, alg, kid, x5u, x5t, x5t256, x5c, ks); 571 } 572 573 // Public / private key pair with 'd' 574 return new ECKey(crv, x, y, d, use, ops, alg, kid, x5u, x5t, x5t256, x5c, ks); 575 576 } catch (IllegalArgumentException e) { 577 throw new IllegalStateException(e.getMessage(), e); 578 } 579 } 580 } 581 582 583 /** 584 * Returns the Base64URL encoding of the specified elliptic curve 'x', 585 * 'y' or 'd' coordinate, with leading zero padding up to the specified 586 * field size in bits. 587 * 588 * @param fieldSize The field size in bits. 589 * @param coordinate The elliptic curve coordinate. Must not be 590 * {@code null}. 591 * 592 * @return The Base64URL-encoded coordinate, with leading zero padding 593 * up to the curve's field size. 594 */ 595 public static Base64URL encodeCoordinate(final int fieldSize, final BigInteger coordinate) { 596 597 final byte[] notPadded = BigIntegerUtils.toBytesUnsigned(coordinate); 598 599 int bytesToOutput = (fieldSize + 7)/8; 600 601 if (notPadded.length >= bytesToOutput) { 602 // Greater-than check to prevent exception on malformed 603 // key below 604 return Base64URL.encode(notPadded); 605 } 606 607 final byte[] padded = new byte[bytesToOutput]; 608 609 System.arraycopy(notPadded, 0, padded, bytesToOutput - notPadded.length, notPadded.length); 610 611 return Base64URL.encode(padded); 612 } 613 614 615 /** 616 * The curve name. 617 */ 618 private final Curve crv; 619 620 621 /** 622 * The public 'x' EC coordinate. 623 */ 624 private final Base64URL x; 625 626 627 /** 628 * The public 'y' EC coordinate. 629 */ 630 private final Base64URL y; 631 632 633 /** 634 * The private 'd' EC coordinate. 635 */ 636 private final Base64URL d; 637 638 639 /** 640 * Private PKCS#11 key handle. 641 */ 642 private final PrivateKey privateKey; 643 644 645 /** 646 * Ensures the specified 'x' and 'y' public coordinates are on the 647 * given curve. 648 * 649 * @param crv The curve. Must not be {@code null}. 650 * @param x The public 'x' coordinate. Must not be {@code null}. 651 * @param y The public 'y' coordinate. Must not be {@code null}. 652 */ 653 private static void ensurePublicCoordinatesOnCurve(final Curve crv, final Base64URL x, final Base64URL y) { 654 655 if (! SUPPORTED_CURVES.contains(crv)) { 656 throw new IllegalArgumentException("Unknown / unsupported curve: " + crv); 657 } 658 659 if (! ECChecks.isPointOnCurve(x.decodeToBigInteger(), y.decodeToBigInteger(), crv.toECParameterSpec())) { 660 throw new IllegalArgumentException("Invalid EC JWK: The 'x' and 'y' public coordinates are not on the " + crv + " curve"); 661 } 662 } 663 664 665 /** 666 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 667 * specified parameters. 668 * 669 * @param crv The cryptographic curve. Must not be {@code null}. 670 * @param x The public 'x' coordinate for the elliptic curve 671 * point. It is represented as the Base64URL encoding of 672 * the coordinate's big endian representation. Must not 673 * be {@code null}. 674 * @param y The public 'y' coordinate for the elliptic curve 675 * point. It is represented as the Base64URL encoding of 676 * the coordinate's big endian representation. Must not 677 * be {@code null}. 678 * @param use The key use, {@code null} if not specified or if the 679 * key is intended for signing as well as encryption. 680 * @param ops The key operations, {@code null} if not specified. 681 * @param alg The intended JOSE algorithm for the key, {@code null} 682 * if not specified. 683 * @param kid The key ID, {@code null} if not specified. 684 * @param x5u The X.509 certificate URL, {@code null} if not 685 * specified. 686 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 687 * if not specified. 688 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 689 * if not specified. 690 * @param x5c The X.509 certificate chain, {@code null} if not 691 * specified. 692 * @param ks Reference to the underlying key store, {@code null} if 693 * not specified. 694 */ 695 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, 696 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 697 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 698 final KeyStore ks) { 699 700 super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5t256, x5c, ks); 701 702 if (crv == null) { 703 throw new IllegalArgumentException("The curve must not be null"); 704 } 705 706 this.crv = crv; 707 708 if (x == null) { 709 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 710 } 711 712 this.x = x; 713 714 if (y == null) { 715 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 716 } 717 718 this.y = y; 719 720 ensurePublicCoordinatesOnCurve(crv, x, y); 721 722 this.d = null; 723 724 this.privateKey = null; 725 } 726 727 728 /** 729 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 730 * with the specified parameters. 731 * 732 * @param crv The cryptographic curve. Must not be {@code null}. 733 * @param x The public 'x' coordinate for the elliptic curve 734 * point. It is represented as the Base64URL encoding of 735 * the coordinate's big endian representation. Must not 736 * be {@code null}. 737 * @param y The public 'y' coordinate for the elliptic curve 738 * point. It is represented as the Base64URL encoding of 739 * the coordinate's big endian representation. Must not 740 * be {@code null}. 741 * @param d The private 'd' 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 use The key use, {@code null} if not specified or if the 746 * key is intended for signing as well as encryption. 747 * @param ops The key operations, {@code null} if not specified. 748 * @param alg The intended JOSE algorithm for the key, {@code null} 749 * if not specified. 750 * @param kid The key ID, {@code null} if not specified. 751 * @param x5u The X.509 certificate URL, {@code null} if not 752 * specified. 753 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 754 * if not specified. 755 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 756 * if not specified. 757 * @param x5c The X.509 certificate chain, {@code null} if not 758 * specified. 759 * @param ks Reference to the underlying key store, {@code null} if 760 * not specified. 761 */ 762 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, final Base64URL d, 763 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 764 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 765 final KeyStore ks) { 766 767 super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5t256, x5c, ks); 768 769 if (crv == null) { 770 throw new IllegalArgumentException("The curve must not be null"); 771 } 772 773 this.crv = crv; 774 775 if (x == null) { 776 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 777 } 778 779 this.x = x; 780 781 if (y == null) { 782 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 783 } 784 785 this.y = y; 786 787 ensurePublicCoordinatesOnCurve(crv, x, y); 788 789 if (d == null) { 790 throw new IllegalArgumentException("The 'd' coordinate must not be null"); 791 } 792 793 this.d = d; 794 795 this.privateKey = null; 796 } 797 798 799 /** 800 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 801 * with the specified parameters. The private key is specified by its 802 * PKCS#11 handle. 803 * 804 * @param crv The cryptographic curve. Must not be {@code null}. 805 * @param x The public 'x' coordinate for the elliptic curve 806 * point. It is represented as the Base64URL encoding of 807 * the coordinate's big endian representation. Must not 808 * be {@code null}. 809 * @param y The public 'y' coordinate for the elliptic curve 810 * point. It is represented as the Base64URL encoding of 811 * the coordinate's big endian representation. Must not 812 * be {@code null}. 813 * @param priv The private key as a PKCS#11 handle, {@code null} if 814 * not specified. 815 * @param use The key use, {@code null} if not specified or if the 816 * key is intended for signing as well as encryption. 817 * @param ops The key operations, {@code null} if not specified. 818 * @param alg The intended JOSE algorithm for the key, {@code null} 819 * if not specified. 820 * @param kid The key ID, {@code null} if not specified. 821 * @param x5u The X.509 certificate URL, {@code null} if not 822 * specified. 823 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 824 * if not specified. 825 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 826 * if not specified. 827 * @param x5c The X.509 certificate chain, {@code null} if not 828 * specified. 829 */ 830 public ECKey(final Curve crv, final Base64URL x, final Base64URL y, final PrivateKey priv, 831 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 832 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 833 final KeyStore ks) { 834 835 super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5t256, x5c, ks); 836 837 if (crv == null) { 838 throw new IllegalArgumentException("The curve must not be null"); 839 } 840 841 this.crv = crv; 842 843 if (x == null) { 844 throw new IllegalArgumentException("The 'x' coordinate must not be null"); 845 } 846 847 this.x = x; 848 849 if (y == null) { 850 throw new IllegalArgumentException("The 'y' coordinate must not be null"); 851 } 852 853 this.y = y; 854 855 ensurePublicCoordinatesOnCurve(crv, x, y); 856 857 d = null; 858 859 this.privateKey = priv; 860 } 861 862 863 /** 864 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 865 * specified parameters. 866 * 867 * @param crv The cryptographic curve. Must not be {@code null}. 868 * @param pub The public EC key to represent. Must not be 869 * {@code null}. 870 * @param use The key use, {@code null} if not specified or if the 871 * key is intended for signing as well as encryption. 872 * @param ops The key operations, {@code null} if not specified. 873 * @param alg The intended JOSE algorithm for the key, {@code null} 874 * if not specified. 875 * @param kid The key ID, {@code null} if not specified. 876 * @param x5u The X.509 certificate URL, {@code null} if not 877 * specified. 878 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 879 * if not specified. 880 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 881 * if not specified. 882 * @param x5c The X.509 certificate chain, {@code null} if not 883 * specified. 884 * @param ks Reference to the underlying key store, {@code null} if 885 * not specified. 886 */ 887 public ECKey(final Curve crv, final ECPublicKey pub, 888 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 889 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 890 final KeyStore ks) { 891 892 this(crv, 893 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 894 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 895 use, ops, alg, kid, 896 x5u, x5t, x5t256, x5c, 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 public ECKey(final Curve crv, final ECPublicKey pub, final ECPrivateKey priv, 928 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 929 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 930 final KeyStore ks) { 931 932 this(crv, 933 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 934 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 935 encodeCoordinate(priv.getParams().getCurve().getField().getFieldSize(), priv.getS()), 936 use, ops, alg, kid, 937 x5u, x5t, x5t256, x5c, 938 ks); 939 } 940 941 942 /** 943 * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 944 * with the specified parameters. The private key is specified by its 945 * PKCS#11 handle. 946 * 947 * @param crv The cryptographic curve. Must not be {@code null}. 948 * @param pub The public EC key to represent. Must not be 949 * {@code null}. 950 * @param priv The private key as a PKCS#11 handle, {@code null} if 951 * not specified. 952 * @param use The key use, {@code null} if not specified or if the 953 * key is intended for signing as well as encryption. 954 * @param ops The key operations, {@code null} if not specified. 955 * @param alg The intended JOSE algorithm for the key, {@code null} 956 * if not specified. 957 * @param kid The key ID, {@code null} if not specified. 958 * @param x5u The X.509 certificate URL, {@code null} if not 959 * specified. 960 * @param x5t The X.509 certificate SHA-1 thumbprint, {@code null} 961 * if not specified. 962 * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null} 963 * if not specified. 964 * @param x5c The X.509 certificate chain, {@code null} if not 965 * specified. 966 * @param ks Reference to the underlying key store, {@code null} if 967 * not specified. 968 */ 969 public ECKey(final Curve crv, final ECPublicKey pub, final PrivateKey priv, 970 final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid, 971 final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c, 972 final KeyStore ks) { 973 974 this( 975 crv, 976 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()), 977 encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()), 978 priv, 979 use, ops, alg, kid, x5u, x5t, x5t256, x5c, 980 ks); 981 } 982 983 984 @Override 985 public Curve getCurve() { 986 987 return crv; 988 } 989 990 991 /** 992 * Gets the public 'x' coordinate for the elliptic curve point. 993 * 994 * @return The 'x' coordinate. It is represented as the Base64URL 995 * encoding of the coordinate's big endian representation. 996 */ 997 public Base64URL getX() { 998 999 return x; 1000 } 1001 1002 1003 /** 1004 * Gets the public 'y' coordinate for the elliptic curve point. 1005 * 1006 * @return The 'y' coordinate. It is represented as the Base64URL 1007 * encoding of the coordinate's big endian representation. 1008 */ 1009 public Base64URL getY() { 1010 1011 return y; 1012 } 1013 1014 1015 /** 1016 * Gets the private 'd' coordinate for the elliptic curve point. It is 1017 * represented as the Base64URL encoding of the coordinate's big endian 1018 * representation. 1019 * 1020 * @return The 'd' coordinate. It is represented as the Base64URL 1021 * encoding of the coordinate's big endian representation. 1022 * {@code null} if not specified (for a public key). 1023 */ 1024 public Base64URL getD() { 1025 1026 return d; 1027 } 1028 1029 1030 /** 1031 * Returns a standard {@code java.security.interfaces.ECPublicKey} 1032 * representation of this Elliptic Curve JWK. Uses the default JCA 1033 * provider. 1034 * 1035 * @return The public Elliptic Curve key. 1036 * 1037 * @throws JOSEException If EC is not supported by the underlying Java 1038 * Cryptography (JCA) provider or if the JWK 1039 * parameters are invalid for a public EC key. 1040 */ 1041 public ECPublicKey toECPublicKey() 1042 throws JOSEException { 1043 1044 return toECPublicKey(null); 1045 } 1046 1047 1048 /** 1049 * Returns a standard {@code java.security.interfaces.ECPublicKey} 1050 * representation of this Elliptic Curve JWK. 1051 * 1052 * @param provider The specific JCA provider to use, {@code null} 1053 * implies the default one. 1054 * 1055 * @return The public Elliptic Curve key. 1056 * 1057 * @throws JOSEException If EC is not supported by the underlying Java 1058 * Cryptography (JCA) provider or if the JWK 1059 * parameters are invalid for a public EC key. 1060 */ 1061 public ECPublicKey toECPublicKey(final Provider provider) 1062 throws JOSEException { 1063 1064 ECParameterSpec spec = crv.toECParameterSpec(); 1065 1066 if (spec == null) { 1067 throw new JOSEException("Couldn't get EC parameter spec for curve " + crv); 1068 } 1069 1070 ECPoint w = new ECPoint(x.decodeToBigInteger(), y.decodeToBigInteger()); 1071 1072 ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(w, spec); 1073 1074 try { 1075 KeyFactory keyFactory; 1076 1077 if (provider == null) { 1078 keyFactory = KeyFactory.getInstance("EC"); 1079 } else { 1080 keyFactory = KeyFactory.getInstance("EC", provider); 1081 } 1082 1083 return (ECPublicKey) keyFactory.generatePublic(publicKeySpec); 1084 1085 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 1086 1087 throw new JOSEException(e.getMessage(), e); 1088 } 1089 } 1090 1091 1092 /** 1093 * Returns a standard {@code java.security.interfaces.ECPrivateKey} 1094 * representation of this Elliptic Curve JWK. Uses the default JCA 1095 * provider. 1096 * 1097 * @return The private Elliptic Curve key, {@code null} if not 1098 * specified by this JWK. 1099 * 1100 * @throws JOSEException If EC is not supported by the underlying Java 1101 * Cryptography (JCA) provider or if the JWK 1102 * parameters are invalid for a private EC key. 1103 */ 1104 public ECPrivateKey toECPrivateKey() 1105 throws JOSEException { 1106 1107 return toECPrivateKey(null); 1108 } 1109 1110 1111 /** 1112 * Returns a standard {@code java.security.interfaces.ECPrivateKey} 1113 * representation of this Elliptic Curve JWK. 1114 * 1115 * @param provider The specific JCA provider to use, {@code null} 1116 * implies the default one. 1117 * 1118 * @return The private Elliptic Curve key, {@code null} if not 1119 * specified by this JWK. 1120 * 1121 * @throws JOSEException If EC is not supported by the underlying Java 1122 * Cryptography (JCA) provider or if the JWK 1123 * parameters are invalid for a private EC key. 1124 */ 1125 public ECPrivateKey toECPrivateKey(final Provider provider) 1126 throws JOSEException { 1127 1128 if (d == null) { 1129 // No private 'd' param 1130 return null; 1131 } 1132 1133 ECParameterSpec spec = crv.toECParameterSpec(); 1134 1135 if (spec == null) { 1136 throw new JOSEException("Couldn't get EC parameter spec for curve " + crv); 1137 } 1138 1139 ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(d.decodeToBigInteger(), spec); 1140 1141 try { 1142 KeyFactory keyFactory; 1143 1144 if (provider == null) { 1145 keyFactory = KeyFactory.getInstance("EC"); 1146 } else { 1147 keyFactory = KeyFactory.getInstance("EC", provider); 1148 } 1149 1150 return (ECPrivateKey) keyFactory.generatePrivate(privateKeySpec); 1151 1152 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 1153 1154 throw new JOSEException(e.getMessage(), e); 1155 } 1156 } 1157 1158 1159 @Override 1160 public PublicKey toPublicKey() 1161 throws JOSEException { 1162 1163 return toECPublicKey(); 1164 } 1165 1166 1167 @Override 1168 public PrivateKey toPrivateKey() 1169 throws JOSEException { 1170 1171 PrivateKey prv = toECPrivateKey(); 1172 1173 if (prv != null) { 1174 // Return private EC key with key material 1175 return prv; 1176 } 1177 1178 // Return private EC key as PKCS#11 handle, or null 1179 return privateKey; 1180 } 1181 1182 1183 /** 1184 * Returns a standard {@code java.security.KeyPair} representation of 1185 * this Elliptic Curve JWK. Uses the default JCA provider. 1186 * 1187 * @return The Elliptic Curve key pair. The private Elliptic Curve key 1188 * will be {@code null} if not specified. 1189 * 1190 * @throws JOSEException If EC is not supported by the underlying Java 1191 * Cryptography (JCA) provider or if the JWK 1192 * parameters are invalid for a public and / or 1193 * private EC key. 1194 */ 1195 @Override 1196 public KeyPair toKeyPair() 1197 throws JOSEException { 1198 1199 return toKeyPair(null); 1200 } 1201 1202 1203 /** 1204 * Returns a standard {@code java.security.KeyPair} representation of 1205 * this Elliptic Curve JWK. 1206 * 1207 * @param provider The specific JCA provider to use, {@code null} 1208 * implies the default one. 1209 * 1210 * @return The Elliptic Curve key pair. The private Elliptic Curve key 1211 * will be {@code null} if not specified. 1212 * 1213 * @throws JOSEException If EC is not supported by the underlying Java 1214 * Cryptography (JCA) provider or if the JWK 1215 * parameters are invalid for a public and / or 1216 * private EC key. 1217 */ 1218 public KeyPair toKeyPair(final Provider provider) 1219 throws JOSEException { 1220 1221 if (privateKey != null) { 1222 // Private key as PKCS#11 handle 1223 return new KeyPair(toECPublicKey(provider), privateKey); 1224 } else { 1225 return new KeyPair(toECPublicKey(provider), toECPrivateKey(provider)); 1226 } 1227 } 1228 1229 1230 @Override 1231 public LinkedHashMap<String,?> getRequiredParams() { 1232 1233 // Put mandatory params in sorted order 1234 LinkedHashMap<String,String> requiredParams = new LinkedHashMap<>(); 1235 requiredParams.put("crv", crv.toString()); 1236 requiredParams.put("kty", getKeyType().getValue()); 1237 requiredParams.put("x", x.toString()); 1238 requiredParams.put("y", y.toString()); 1239 return requiredParams; 1240 } 1241 1242 1243 @Override 1244 public boolean isPrivate() { 1245 1246 return d != null || privateKey != null; 1247 } 1248 1249 1250 @Override 1251 public int size() { 1252 1253 ECParameterSpec ecParameterSpec = crv.toECParameterSpec(); 1254 1255 if (ecParameterSpec == null) { 1256 throw new UnsupportedOperationException("Couldn't determine field size for curve " + crv.getName()); 1257 } 1258 1259 return ecParameterSpec.getCurve().getField().getFieldSize(); 1260 } 1261 1262 1263 /** 1264 * Returns a copy of this Elliptic Curve JWK with any private values 1265 * removed. 1266 * 1267 * @return The copied public Elliptic Curve JWK. 1268 */ 1269 @Override 1270 public ECKey toPublicJWK() { 1271 1272 return new ECKey( 1273 getCurve(), getX(), getY(), 1274 getKeyUse(), getKeyOperations(), getAlgorithm(), getKeyID(), 1275 getX509CertURL(), getX509CertThumbprint(), getX509CertSHA256Thumbprint(), getX509CertChain(), 1276 getKeyStore()); 1277 } 1278 1279 1280 @Override 1281 public JSONObject toJSONObject() { 1282 1283 JSONObject o = super.toJSONObject(); 1284 1285 // Append EC specific attributes 1286 o.put("crv", crv.toString()); 1287 o.put("x", x.toString()); 1288 o.put("y", y.toString()); 1289 1290 if (d != null) { 1291 o.put("d", d.toString()); 1292 } 1293 1294 return o; 1295 } 1296 1297 1298 /** 1299 * Parses a public / private Elliptic Curve JWK from the specified JSON 1300 * object string representation. 1301 * 1302 * @param s The JSON object string to parse. Must not be {@code null}. 1303 * 1304 * @return The public / private Elliptic Curve JWK. 1305 * 1306 * @throws ParseException If the string couldn't be parsed to an 1307 * Elliptic Curve JWK. 1308 */ 1309 public static ECKey parse(final String s) 1310 throws ParseException { 1311 1312 return parse(JSONObjectUtils.parse(s)); 1313 } 1314 1315 1316 /** 1317 * Parses a public / private Elliptic Curve JWK from the specified JSON 1318 * object representation. 1319 * 1320 * @param jsonObject The JSON object to parse. Must not be 1321 * {@code null}. 1322 * 1323 * @return The public / private Elliptic Curve JWK. 1324 * 1325 * @throws ParseException If the JSON object couldn't be parsed to an 1326 * Elliptic Curve JWK. 1327 */ 1328 public static ECKey parse(final JSONObject jsonObject) 1329 throws ParseException { 1330 1331 // Parse the mandatory parameters first 1332 Curve crv = Curve.parse(JSONObjectUtils.getString(jsonObject, "crv")); 1333 Base64URL x = new Base64URL(JSONObjectUtils.getString(jsonObject, "x")); 1334 Base64URL y = new Base64URL(JSONObjectUtils.getString(jsonObject, "y")); 1335 1336 // Check key type 1337 KeyType kty = JWKMetadata.parseKeyType(jsonObject); 1338 1339 if (kty != KeyType.EC) { 1340 throw new ParseException("The key type \"kty\" must be EC", 0); 1341 } 1342 1343 // Get optional private key 1344 Base64URL d = null; 1345 if (jsonObject.get("d") != null) { 1346 d = new Base64URL(JSONObjectUtils.getString(jsonObject, "d")); 1347 } 1348 1349 1350 try { 1351 if (d == null) { 1352 // Public key 1353 return new ECKey(crv, x, y, 1354 JWKMetadata.parseKeyUse(jsonObject), 1355 JWKMetadata.parseKeyOperations(jsonObject), 1356 JWKMetadata.parseAlgorithm(jsonObject), 1357 JWKMetadata.parseKeyID(jsonObject), 1358 JWKMetadata.parseX509CertURL(jsonObject), 1359 JWKMetadata.parseX509CertThumbprint(jsonObject), 1360 JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject), 1361 JWKMetadata.parseX509CertChain(jsonObject), 1362 null); 1363 1364 } else { 1365 // Key pair 1366 return new ECKey(crv, x, y, d, 1367 JWKMetadata.parseKeyUse(jsonObject), 1368 JWKMetadata.parseKeyOperations(jsonObject), 1369 JWKMetadata.parseAlgorithm(jsonObject), 1370 JWKMetadata.parseKeyID(jsonObject), 1371 JWKMetadata.parseX509CertURL(jsonObject), 1372 JWKMetadata.parseX509CertThumbprint(jsonObject), 1373 JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject), 1374 JWKMetadata.parseX509CertChain(jsonObject), 1375 null); 1376 } 1377 1378 } catch (IllegalArgumentException ex) { 1379 1380 // Conflicting 'use' and 'key_ops' 1381 throw new ParseException(ex.getMessage(), 0); 1382 } 1383 } 1384 1385 1386 /** 1387 * Parses a public Elliptic Curve JWK from the specified X.509 1388 * certificate. Requires BouncyCastle. 1389 * 1390 * <p><strong>Important:</strong> The X.509 certificate is not 1391 * validated! 1392 * 1393 * <p>Sets the following JWK parameters: 1394 * 1395 * <ul> 1396 * <li>The curve is obtained from the subject public key info 1397 * algorithm parameters. 1398 * <li>The JWK use inferred by {@link KeyUse#from}. 1399 * <li>The JWK ID from the X.509 serial number (in base 10). 1400 * <li>The JWK X.509 certificate chain (this certificate only). 1401 * <li>The JWK X.509 certificate SHA-256 thumbprint. 1402 * </ul> 1403 * 1404 * @param cert The X.509 certificate. Must not be {@code null}. 1405 * 1406 * @return The public Elliptic Curve JWK. 1407 * 1408 * @throws JOSEException If parsing failed. 1409 */ 1410 public static ECKey parse(final X509Certificate cert) 1411 throws JOSEException { 1412 1413 if (! (cert.getPublicKey() instanceof ECPublicKey)) { 1414 throw new JOSEException("The public key of the X.509 certificate is not EC"); 1415 } 1416 1417 ECPublicKey publicKey = (ECPublicKey) cert.getPublicKey(); 1418 1419 try { 1420 JcaX509CertificateHolder certHolder = new JcaX509CertificateHolder(cert); 1421 1422 String oid = certHolder.getSubjectPublicKeyInfo().getAlgorithm().getParameters().toString(); 1423 1424 Curve crv = Curve.forOID(oid); 1425 1426 if (crv == null) { 1427 throw new JOSEException("Couldn't determine EC JWK curve for OID " + oid); 1428 } 1429 1430 MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); 1431 1432 return new ECKey.Builder(crv, publicKey) 1433 .keyUse(KeyUse.from(cert)) 1434 .keyID(cert.getSerialNumber().toString(10)) 1435 .x509CertChain(Collections.singletonList(Base64.encode(cert.getEncoded()))) 1436 .x509CertSHA256Thumbprint(Base64URL.encode(sha256.digest(cert.getEncoded()))) 1437 .build(); 1438 } catch (NoSuchAlgorithmException e) { 1439 throw new JOSEException("Couldn't encode x5t parameter: " + e.getMessage(), e); 1440 } catch (CertificateEncodingException e) { 1441 throw new JOSEException("Couldn't encode x5c parameter: " + e.getMessage(), e); 1442 } 1443 } 1444 1445 1446 /** 1447 * Loads a public / private Elliptic Curve JWK from the specified JCA 1448 * key store. Requires BouncyCastle. 1449 * 1450 * <p><strong>Important:</strong> The X.509 certificate is not 1451 * validated! 1452 * 1453 * @param keyStore The key store. Must not be {@code null}. 1454 * @param alias The alias. Must not be {@code null}. 1455 * @param pin The pin to unlock the private key if any, empty or 1456 * {@code null} if not required. 1457 * 1458 * @return The public / private Elliptic Curve JWK., {@code null} if no 1459 * key with the specified alias was found. 1460 * 1461 * @throws KeyStoreException On a key store exception. 1462 * @throws JOSEException If EC key loading failed. 1463 */ 1464 public static ECKey load(final KeyStore keyStore, 1465 final String alias, 1466 final char[] pin) 1467 throws KeyStoreException, JOSEException { 1468 1469 Certificate cert = keyStore.getCertificate(alias); 1470 1471 if (cert == null || ! (cert instanceof X509Certificate)) { 1472 return null; 1473 } 1474 1475 X509Certificate x509Cert = (X509Certificate)cert; 1476 1477 if (! (x509Cert.getPublicKey() instanceof ECPublicKey)) { 1478 throw new JOSEException("Couldn't load EC JWK: The key algorithm is not EC"); 1479 } 1480 1481 ECKey ecJWK = ECKey.parse(x509Cert); 1482 1483 // Let kid=alias 1484 ecJWK = new ECKey.Builder(ecJWK).keyID(alias).keyStore(keyStore).build(); 1485 1486 // Check for private counterpart 1487 Key key; 1488 try { 1489 key = keyStore.getKey(alias, pin); 1490 } catch (UnrecoverableKeyException | NoSuchAlgorithmException e) { 1491 throw new JOSEException("Couldn't retrieve private EC key (bad pin?): " + e.getMessage(), e); 1492 } 1493 1494 if (key instanceof ECPrivateKey) { 1495 // Simple file based key store 1496 return new ECKey.Builder(ecJWK) 1497 .privateKey((ECPrivateKey)key) 1498 .build(); 1499 } else if (key instanceof PrivateKey && "EC".equalsIgnoreCase(key.getAlgorithm())) { 1500 // PKCS#11 store 1501 return new ECKey.Builder(ecJWK) 1502 .privateKey((PrivateKey)key) 1503 .build(); 1504 } else { 1505 return ecJWK; 1506 } 1507 } 1508}