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-04-27
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 boolean matches(final X509Certificate cert) {
1854                
1855                ECPublicKey certECKey;
1856                try {
1857                        certECKey = (ECPublicKey) getParsedX509CertChain().get(0).getPublicKey();
1858                } catch (ClassCastException ex) {
1859                        return false;
1860                }
1861                // Compare Big Ints, base64url encoding may have padding!
1862                // https://tools.ietf.org/html/rfc7518#section-6.2.1.2
1863                if (! getX().decodeToBigInteger().equals(certECKey.getW().getAffineX())) {
1864                        return false;
1865                }
1866                return getY().decodeToBigInteger().equals(certECKey.getW().getAffineY());
1867        }
1868        
1869        
1870        /**
1871         * Calls {@link #matches(X509Certificate)} for the first X.509
1872         * certificate in the specified chain.
1873         *
1874         * @param chain The X.509 certificate chain, {@code null} if not
1875         *              specified.
1876         *
1877         * @throws IllegalArgumentException If a certificate chain is specified
1878         *                                  and the first certificate in it
1879         *                                  doesn't match.
1880         */
1881        private void ensureMatches(final List<X509Certificate> chain) {
1882                
1883                if (chain == null)
1884                        return;
1885                
1886                if (! matches(chain.get(0)))
1887                        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");
1888        }
1889        
1890        
1891        @Override
1892        public LinkedHashMap<String,?> getRequiredParams() {
1893
1894                // Put mandatory params in sorted order
1895                LinkedHashMap<String,String> requiredParams = new LinkedHashMap<>();
1896                requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE, crv.toString());
1897                requiredParams.put(JWKParameterNames.KEY_TYPE, getKeyType().getValue());
1898                requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE_X_COORDINATE, x.toString());
1899                requiredParams.put(JWKParameterNames.ELLIPTIC_CURVE_Y_COORDINATE, y.toString());
1900                return requiredParams;
1901        }
1902
1903
1904        @Override
1905        public boolean isPrivate() {
1906
1907                return d != null || privateKey != null;
1908        }
1909
1910
1911        @Override
1912        public int size() {
1913
1914                ECParameterSpec ecParameterSpec = crv.toECParameterSpec();
1915
1916                if (ecParameterSpec == null) {
1917                        throw new UnsupportedOperationException("Couldn't determine field size for curve " + crv.getName());
1918                }
1919
1920                return ecParameterSpec.getCurve().getField().getFieldSize();
1921        }
1922
1923        
1924        /**
1925         * Returns a copy of this Elliptic Curve JWK with any private values 
1926         * removed.
1927         *
1928         * @return The copied public Elliptic Curve JWK.
1929         */
1930        @Override
1931        public ECKey toPublicJWK() {
1932
1933                return new ECKey(
1934                        getCurve(), getX(), getY(),
1935                        getKeyUse(), getKeyOperations(), getAlgorithm(), getKeyID(),
1936                        getX509CertURL(), getX509CertThumbprint(), getX509CertSHA256Thumbprint(), getX509CertChain(),
1937                        getExpirationTime(), getNotBeforeTime(), getIssueTime(), getKeyRevocation(),
1938                        getKeyStore());
1939        }
1940        
1941
1942        @Override
1943        public Map<String, Object> toJSONObject() {
1944
1945                Map<String, Object> o = super.toJSONObject();
1946
1947                // Append EC specific attributes
1948                o.put(JWKParameterNames.ELLIPTIC_CURVE, crv.toString());
1949                o.put(JWKParameterNames.ELLIPTIC_CURVE_X_COORDINATE, x.toString());
1950                o.put(JWKParameterNames.ELLIPTIC_CURVE_Y_COORDINATE, y.toString());
1951
1952                if (d != null) {
1953                        o.put(JWKParameterNames.ELLIPTIC_CURVE_PRIVATE_KEY, d.toString());
1954                }
1955                
1956                return o;
1957        }
1958
1959
1960        /**
1961         * Parses a public / private Elliptic Curve JWK from the specified JSON
1962         * object string representation.
1963         *
1964         * @param s The JSON object string to parse. Must not be {@code null}.
1965         *
1966         * @return The public / private Elliptic Curve JWK.
1967         *
1968         * @throws ParseException If the string couldn't be parsed to an
1969         *                        Elliptic Curve JWK.
1970         */
1971        public static ECKey parse(final String s)
1972                throws ParseException {
1973
1974                return parse(JSONObjectUtils.parse(s));
1975        }
1976
1977
1978        /**
1979         * Parses a public / private Elliptic Curve JWK from the specified JSON
1980         * object representation.
1981         *
1982         * @param jsonObject The JSON object to parse. Must not be 
1983         *                   {@code null}.
1984         *
1985         * @return The public / private Elliptic Curve JWK.
1986         *
1987         * @throws ParseException If the JSON object couldn't be parsed to an 
1988         *                        Elliptic Curve JWK.
1989         */
1990        public static ECKey parse(final Map<String, Object> jsonObject)
1991                throws ParseException {
1992
1993                // Check key type
1994                if (! KeyType.EC.equals(JWKMetadata.parseKeyType(jsonObject))) {
1995                        throw new ParseException("The key type \"kty\" must be EC", 0);
1996                }
1997                
1998                // Parse the mandatory public key parameters
1999                Curve crv;
2000                try {
2001                        crv = Curve.parse(JSONObjectUtils.getString(jsonObject, JWKParameterNames.ELLIPTIC_CURVE));
2002                } catch (IllegalArgumentException e) {
2003                        throw new ParseException(e.getMessage(), 0);
2004                }
2005                
2006                Base64URL x = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.ELLIPTIC_CURVE_X_COORDINATE);
2007                Base64URL y = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.ELLIPTIC_CURVE_Y_COORDINATE);
2008
2009                // Get optional private key
2010                Base64URL d = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.ELLIPTIC_CURVE_PRIVATE_KEY);
2011                
2012                try {
2013                        if (d == null) {
2014                                // Public key
2015                                return new ECKey(crv, x, y,
2016                                        JWKMetadata.parseKeyUse(jsonObject),
2017                                        JWKMetadata.parseKeyOperations(jsonObject),
2018                                        JWKMetadata.parseAlgorithm(jsonObject),
2019                                        JWKMetadata.parseKeyID(jsonObject),
2020                                        JWKMetadata.parseX509CertURL(jsonObject),
2021                                        JWKMetadata.parseX509CertThumbprint(jsonObject),
2022                                        JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject),
2023                                        JWKMetadata.parseX509CertChain(jsonObject),
2024                                        JWKMetadata.parseExpirationTime(jsonObject),
2025                                        JWKMetadata.parseNotBeforeTime(jsonObject),
2026                                        JWKMetadata.parseIssueTime(jsonObject),
2027                                        JWKMetadata.parseKeyRevocation(jsonObject),
2028                                        null);
2029
2030                        } else {
2031                                // Key pair
2032                                return new ECKey(crv, x, y, d,
2033                                        JWKMetadata.parseKeyUse(jsonObject),
2034                                        JWKMetadata.parseKeyOperations(jsonObject),
2035                                        JWKMetadata.parseAlgorithm(jsonObject),
2036                                        JWKMetadata.parseKeyID(jsonObject),
2037                                        JWKMetadata.parseX509CertURL(jsonObject),
2038                                        JWKMetadata.parseX509CertThumbprint(jsonObject),
2039                                        JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject),
2040                                        JWKMetadata.parseX509CertChain(jsonObject),
2041                                        JWKMetadata.parseExpirationTime(jsonObject),
2042                                        JWKMetadata.parseNotBeforeTime(jsonObject),
2043                                        JWKMetadata.parseIssueTime(jsonObject),
2044                                        JWKMetadata.parseKeyRevocation(jsonObject),
2045                                        null);
2046                        }
2047
2048                } catch (Exception ex) {
2049
2050                        // Missing x or y, conflicting 'use' and 'key_ops'
2051                        throw new ParseException(ex.getMessage(), 0);
2052                }
2053        }
2054        
2055        
2056        /**
2057         * Parses a public Elliptic Curve JWK from the specified X.509
2058         * certificate. Requires BouncyCastle.
2059         *
2060         * <p><strong>Important:</strong> The X.509 certificate is not
2061         * validated!
2062         *
2063         * <p>Sets the following JWK parameters:
2064         *
2065         * <ul>
2066         *     <li>The curve is obtained from the subject public key info
2067         *         algorithm parameters.
2068         *     <li>The JWK use inferred by {@link KeyUse#from}.
2069         *     <li>The JWK ID from the X.509 serial number (in base 10).
2070         *     <li>The JWK X.509 certificate chain (this certificate only).
2071         *     <li>The JWK X.509 certificate SHA-256 thumbprint.
2072         * </ul>
2073         *
2074         * @param cert The X.509 certificate. Must not be {@code null}.
2075         *
2076         * @return The public Elliptic Curve JWK.
2077         *
2078         * @throws JOSEException If parsing failed.
2079         */
2080        public static ECKey parse(final X509Certificate cert)
2081                throws JOSEException {
2082                
2083                if (! (cert.getPublicKey() instanceof ECPublicKey)) {
2084                        throw new JOSEException("The public key of the X.509 certificate is not EC");
2085                }
2086                
2087                ECPublicKey publicKey = (ECPublicKey) cert.getPublicKey();
2088                
2089                try {
2090                        JcaX509CertificateHolder certHolder = new JcaX509CertificateHolder(cert);
2091                        
2092                        String oid = certHolder.getSubjectPublicKeyInfo().getAlgorithm().getParameters().toString();
2093                        
2094                        Curve crv = Curve.forOID(oid);
2095                        
2096                        if (crv == null) {
2097                                throw new JOSEException("Couldn't determine EC JWK curve for OID " + oid);
2098                        }
2099                        
2100                        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
2101                        
2102                        return new ECKey.Builder(crv, publicKey)
2103                                .keyUse(KeyUse.from(cert))
2104                                .keyID(cert.getSerialNumber().toString(10))
2105                                .x509CertChain(Collections.singletonList(Base64.encode(cert.getEncoded())))
2106                                .x509CertSHA256Thumbprint(Base64URL.encode(sha256.digest(cert.getEncoded())))
2107                                .expirationTime(cert.getNotAfter())
2108                                .notBeforeTime(cert.getNotBefore())
2109                                .build();
2110                } catch (NoSuchAlgorithmException e) {
2111                        throw new JOSEException("Couldn't encode x5t parameter: " + e.getMessage(), e);
2112                } catch (CertificateEncodingException e) {
2113                        throw new JOSEException("Couldn't encode x5c parameter: " + e.getMessage(), e);
2114                }
2115        }
2116        
2117        
2118        /**
2119         * Loads a public / private Elliptic Curve JWK from the specified JCA
2120         * key store. Requires BouncyCastle.
2121         *
2122         * <p><strong>Important:</strong> The X.509 certificate is not
2123         * validated!
2124         *
2125         * @param keyStore The key store. Must not be {@code null}.
2126         * @param alias    The alias. Must not be {@code null}.
2127         * @param pin      The pin to unlock the private key if any, empty or
2128         *                 {@code null} if not required.
2129         *
2130         * @return The public / private Elliptic Curve JWK., {@code null} if no
2131         *         key with the specified alias was found.
2132         *
2133         * @throws KeyStoreException On a key store exception.
2134         * @throws JOSEException     If EC key loading failed.
2135         */
2136        public static ECKey load(final KeyStore keyStore,
2137                                 final String alias,
2138                                 final char[] pin)
2139                throws KeyStoreException, JOSEException {
2140                
2141                Certificate cert = keyStore.getCertificate(alias);
2142                
2143                if (!(cert instanceof X509Certificate)) {
2144                        return null;
2145                }
2146                
2147                X509Certificate x509Cert = (X509Certificate)cert;
2148                
2149                if (! (x509Cert.getPublicKey() instanceof ECPublicKey)) {
2150                        throw new JOSEException("Couldn't load EC JWK: The key algorithm is not EC");
2151                }
2152                        
2153                ECKey ecJWK = ECKey.parse(x509Cert);
2154                
2155                // Let kid=alias
2156                ecJWK = new ECKey.Builder(ecJWK).keyID(alias).keyStore(keyStore).build();
2157                
2158                // Check for private counterpart
2159                Key key;
2160                try {
2161                        key = keyStore.getKey(alias, pin);
2162                } catch (UnrecoverableKeyException | NoSuchAlgorithmException e) {
2163                        throw new JOSEException("Couldn't retrieve private EC key (bad pin?): " + e.getMessage(), e);
2164                }
2165                        
2166                if (key instanceof ECPrivateKey) {
2167                        // Simple file based key store
2168                        return new ECKey.Builder(ecJWK)
2169                                .privateKey((ECPrivateKey)key)
2170                                .build();
2171                } else if (key instanceof PrivateKey && "EC".equalsIgnoreCase(key.getAlgorithm())) {
2172                        // PKCS#11 store
2173                        return new ECKey.Builder(ecJWK)
2174                                .privateKey((PrivateKey)key)
2175                                .build();
2176                } else {
2177                        return ecJWK;
2178                }
2179        }
2180
2181        
2182        @Override
2183        public boolean equals(Object o) {
2184                if (this == o) return true;
2185                if (!(o instanceof ECKey)) return false;
2186                if (!super.equals(o)) return false;
2187                ECKey ecKey = (ECKey) o;
2188                return Objects.equals(crv, ecKey.crv) &&
2189                                Objects.equals(x, ecKey.x) &&
2190                                Objects.equals(y, ecKey.y) &&
2191                                Objects.equals(d, ecKey.d) &&
2192                                Objects.equals(privateKey, ecKey.privateKey);
2193        }
2194
2195        
2196        @Override
2197        public int hashCode() {
2198                return Objects.hash(super.hashCode(), crv, x, y, d, privateKey);
2199        }
2200}