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