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