001package com.nimbusds.jose.jwk;
002
003
004import java.math.BigInteger;
005import java.net.URL;
006import java.util.List;
007import java.security.KeyFactory;
008import java.security.KeyPair;
009import java.security.NoSuchAlgorithmException;
010import java.security.interfaces.ECPrivateKey;
011import java.security.interfaces.ECPublicKey;
012import java.security.spec.ECParameterSpec;
013import java.security.spec.ECPoint;
014import java.security.spec.ECPrivateKeySpec;
015import java.security.spec.ECPublicKeySpec;
016import java.security.spec.InvalidKeySpecException;
017import java.text.ParseException;
018import java.util.Set;
019
020import net.jcip.annotations.Immutable;
021
022import net.minidev.json.JSONObject;
023
024import org.bouncycastle.jce.ECNamedCurveTable;
025import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
026import org.bouncycastle.jce.spec.ECNamedCurveSpec;
027
028import com.nimbusds.jose.Algorithm;
029import com.nimbusds.jose.crypto.BouncyCastleProviderSingleton;
030import com.nimbusds.jose.util.*;
031
032
033/**
034 * Public and private {@link KeyType#EC Elliptic Curve} JSON Web Key (JWK). 
035 * Uses the BouncyCastle.org provider for EC key import and export. This class
036 * is immutable.
037 *
038 * <p>Example JSON object representation of a public EC JWK:
039 * 
040 * <pre>
041 * {
042 *   "kty" : "EC",
043 *   "crv" : "P-256",
044 *   "x"   : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
045 *   "y"   : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
046 *   "use" : "enc",
047 *   "kid" : "1"
048 * }
049 * </pre>
050 *
051 * <p>Example JSON object representation of a public and private EC JWK:
052 *
053 * <pre>
054 * {
055 *   "kty" : "EC",
056 *   "crv" : "P-256",
057 *   "x"   : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
058 *   "y"   : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
059 *   "d"   : "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE",
060 *   "use" : "enc",
061 *   "kid" : "1"
062 * }
063 * </pre>
064 *
065 * <p>See http://en.wikipedia.org/wiki/Elliptic_curve_cryptography
066 *
067 * @author Vladimir Dzhuvinov
068 * @author Justin Richer
069 * @version $version$ (2014-04-02)
070 */
071@Immutable
072public final class ECKey extends JWK {
073
074
075        /**
076         * Cryptographic curve. This class is immutable.
077         *
078         * <p>Includes constants for the following standard cryptographic 
079         * curves:
080         *
081         * <ul>
082         *     <li>{@link #P_256}
083         *     <li>{@link #P_384}
084         *     <li>{@link #P_521}
085         * </ul>
086         *
087         * <p>See "Digital Signature Standard (DSS)", FIPS PUB 186-3, June 
088         * 2009, National Institute of Standards and Technology (NIST).
089         */
090        @Immutable
091        public static class Curve {
092
093
094                /**
095                 * P-256 curve (secp256r1).
096                 */
097                public static final Curve P_256 = new Curve("P-256", "secp256r1");
098
099
100                /**
101                 * P-384 curve (secp384r1).
102                 */
103                public static final Curve P_384 = new Curve("P-384", "secp384r1");
104
105
106                /**
107                 * P-521 curve (secp521r1).
108                 */
109                public static final Curve P_521 = new Curve("P-521", "secp521r1");
110
111
112                /**
113                 * The JOSE curve name.
114                 */
115                private final String name;
116
117
118                /**
119                 * The standard (JCA) curve name, {@code null} if not 
120                 * specified.
121                 */
122                private final String stdName;
123
124
125                /**
126                 * Creates a new cryptographic curve with the specified name.
127                 * The standard (JCA) curve name is not unspecified.
128                 *
129                 * @param name The name of the cryptographic curve. Must not be
130                 *             {@code null}.
131                 */
132                public Curve(final String name) {
133
134                        this(name, null);
135                }
136
137
138                /**
139                 * Creates a new cryptographic curve with the specified name.
140                 *
141                 * @param name    The JOSE name of the cryptographic curve. 
142                 *                Must not be {@code null}.
143                 * @param stdName The standard (JCA) name of the cryptographic
144                 *                curve, {@code null} if not specified.
145                 */
146                public Curve(final String name, final String stdName) {
147
148                        if (name == null) {
149                                throw new IllegalArgumentException("The cryptographic curve name must not be null");
150                        }
151
152                        this.name = name;
153
154                        this.stdName = stdName;
155                }
156
157
158                /**
159                 * Gets the name of this cryptographic curve.
160                 *
161                 * @return The name.
162                 */
163                public String getName() {
164
165                        return name;
166                }
167
168
169                /**
170                 * Gets the standard (JCA) name of this cryptographic curve.
171                 *
172                 * @return The standard (JCA) name.
173                 */
174                public String getStdName() {
175
176                        return stdName;
177                }
178
179
180                /**
181                 * Gets the Elliptic Curve parameter specification for this
182                 * cryptographic curve.
183                 *
184                 * @return The EC parameter specification, {@code null} if this
185                 *         cryptographic curve has no standard (JCA) name 
186                 *         specified or if lookup of the EC parameters failed.
187                 */
188                public ECParameterSpec toECParameterSpec() {
189
190                        if (stdName == null) {
191                                return null;
192                        }
193
194                        ECNamedCurveParameterSpec curveParams = 
195                                ECNamedCurveTable.getParameterSpec(stdName);
196
197                        if (curveParams == null) {
198                                return null;
199                        }
200
201                        return new ECNamedCurveSpec(curveParams.getName(),
202                                                    curveParams.getCurve(),
203                                                    curveParams.getG(),
204                                                    curveParams.getN());
205                }
206
207
208                /**
209                 * @see #getName
210                 */
211                @Override
212                public String toString() {
213
214                        return getName();
215                }
216
217
218                /**
219                 * Overrides {@code Object.equals()}.
220                 *
221                 * @param object The object to compare to.
222                 *
223                 * @return {@code true} if the objects have the same value,
224                 *         otherwise {@code false}.
225                 */
226                @Override
227                public boolean equals(final Object object) {
228
229                        return object instanceof Curve &&
230                               this.toString().equals(object.toString());
231                }
232
233
234                /**
235                 * Parses a cryptographic curve from the specified string.
236                 *
237                 * @param s The string to parse. Must not be {@code null}.
238                 *
239                 * @return The cryptographic curve.
240                 *
241                 * @throws ParseException If the string couldn't be parsed.
242                 */
243                public static Curve parse(final String s) 
244                        throws ParseException {
245
246                        if (s == null) {
247                                throw new IllegalArgumentException("The cryptographic curve string must not be null");
248                        }
249
250                        if (s.equals(P_256.getName())) {
251                                return P_256;
252
253                        } else if (s.equals(P_384.getName())) {
254                                return P_384;
255
256                        } else if (s.equals(P_521.getName())) {
257                                return P_521;
258
259                        } else {
260                                return new Curve(s);
261                        }
262                }
263
264
265                /**
266                 * Gets the cryptographic curve for the specified standard 
267                 * (JCA) name.
268                 *
269                 * @param stdName The standard (JCA) name. Must not be 
270                 *                {@code null}.
271                 *
272                 * @throws IllegalArgumentException If no matching JOSE curve 
273                 *                                  constant could be found.
274                 */
275                public static Curve forStdName(final String stdName) {
276
277                        if (stdName.equals("secp256r1")) {
278                                return P_256;
279                        } else if (stdName.equals("secp384r1")) {
280                                return P_384;
281                        } else if (stdName.equals("secp521r1")) {
282                                return P_521;
283                        } else {
284                                throw new IllegalArgumentException("No matching curve constant for standard (JCA) name " + stdName);
285                        }
286                }
287        }
288
289
290        /**
291         * Builder for constructing Elliptic Curve JWKs.
292         *
293         * <p>Example use:
294         *
295         * <pre>
296         * ECKey key = new ECKey.Builder(Curve.P521, x, y).
297         *             d(d).
298         *             algorithm(JWSAlgorithm.ES512).
299         *             keyID("789").
300         *             build();
301         * </pre>
302         */
303        public static class Builder {
304
305
306                /**
307                 * The curve name.
308                 */
309                private final Curve crv;
310
311
312                /**
313                 * The public 'x' EC coordinate.
314                 */
315                private final Base64URL x;
316
317
318                /**
319                 * The public 'y' EC coordinate.
320                 */
321                private final Base64URL y;
322                
323
324                /**
325                 * The private 'd' EC coordinate, optional.
326                 */
327                private Base64URL d;
328
329
330                /**
331                 * The public key use, optional.
332                 */
333                private KeyUse use;
334
335
336                /**
337                 * The key operations, optional.
338                 */
339                private Set<KeyOperation> ops;
340
341
342                /**
343                 * The intended JOSE algorithm for the key, optional.
344                 */
345                private Algorithm alg;
346
347
348                /**
349                 * The key ID, optional.
350                 */
351                private String kid;
352
353
354                /**
355                 * X.509 certificate URL, optional.
356                 */
357                private URL x5u;
358
359
360                /**
361                 * X.509 certificate thumbprint, optional.
362                 */
363                private Base64URL x5t;
364
365
366                /**
367                 * The X.509 certificate chain, optional.
368                 */
369                private List<Base64> x5c;
370
371
372                /**
373                 * Creates a new Elliptic Curve JWK builder.
374                 *
375                 * @param crv The cryptographic curve. Must not be 
376                 *            {@code null}.
377                 * @param x   The public 'x' coordinate for the elliptic curve 
378                 *            point. It is represented as the Base64URL 
379                 *            encoding of the coordinate's big endian 
380                 *            representation. Must not be {@code null}.
381                 * @param y   The public 'y' coordinate for the elliptic curve 
382                 *            point. It is represented as the Base64URL 
383                 *            encoding of the coordinate's big endian 
384                 *            representation. Must not be {@code null}.
385                 */
386                public Builder(final Curve crv, final Base64URL x, final Base64URL y) {
387
388                        if (crv == null) {
389                                throw new IllegalArgumentException("The curve must not be null");
390                        }
391
392                        this.crv = crv;
393
394                        if (x == null) {
395                                throw new IllegalArgumentException("The 'x' coordinate must not be null");
396                        }
397
398                        this.x = x;
399
400                        if (y == null) {
401                                throw new IllegalArgumentException("The 'y' coordinate must not be null");
402                        }
403
404                        this.y = y;
405                }
406
407
408                /**
409                 * Creates a new Elliptic Curve JWK builder.
410                 *
411                 * @param crv The cryptographic curve. Must not be 
412                 *            {@code null}.
413                 * @param pub The public EC key to represent. Must not be 
414                 *            {@code null}.
415                 */
416                public Builder(final Curve crv, final ECPublicKey pub) {
417
418                        this(crv,
419                             encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()),
420                             encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()));
421                }
422
423
424                /**
425                 * Sets the private 'd' coordinate for the elliptic curve 
426                 * point. The alternative method is {@link #privateKey}.
427                 *
428                 * @param d The 'd' coordinate. It is represented as the 
429                 *          Base64URL encoding of the coordinate's big endian 
430                 *          representation. {@code null} if not specified (for
431                 *          a public key).
432                 *
433                 * @return This builder.
434                 */
435                public Builder d(final Base64URL d) {
436
437                        this.d = d;
438                        return this;
439                }
440
441
442                /**
443                 * Sets the private Elliptic Curve key. The alternative method 
444                 * is {@link #d}.
445                 *
446                 * @param priv The private EC key, used to obtain the private
447                 *             'd' coordinate for the elliptic curve point.
448                 *             {@code null} if not specified (for a public 
449                 *             key).
450                 *
451                 * @return This builder.
452                 */
453                public Builder privateKey(final ECPrivateKey priv) {
454
455                        if (priv != null) {
456                                this.d = encodeCoordinate(priv.getParams().getCurve().getField().getFieldSize(), priv.getS());
457                        }
458                        
459                        return this;
460                }
461
462
463                /**
464                 * Sets the use ({@code use}) of the JWK (for a public key).
465                 *
466                 * @param use The key use, {@code null} if not specified or if 
467                 *            the key is intended for signing as well as 
468                 *            encryption.
469                 *
470                 * @return This builder.
471                 */
472                public Builder keyUse(final KeyUse use) {
473
474                        this.use = use;
475                        return this;
476                }
477
478
479                /**
480                 * Sets the operations ({@code key_ops}) of the JWK (for a
481                 * non-public key).
482                 *
483                 * @param ops The key operations, {@code null} if not
484                 *            specified.
485                 *
486                 * @return This builder.
487                 */
488                public Builder keyOperations(final Set<KeyOperation> ops) {
489
490                        this.ops = ops;
491                        return this;
492                }
493
494
495                /**
496                 * Sets the intended JOSE algorithm ({@code alg}) for the JWK.
497                 *
498                 * @param alg The intended JOSE algorithm, {@code null} if not 
499                 *            specified.
500                 *
501                 * @return This builder.
502                 */
503                public Builder algorithm(final Algorithm alg) {
504
505                        this.alg = alg;
506                        return this;
507                }
508
509                /**
510                 * Sets the ID ({@code kid}) of the JWK. The key ID can be used 
511                 * to match a specific key. This can be used, for instance, to 
512                 * choose a key within a {@link JWKSet} during key rollover. 
513                 * The key ID may also correspond to a JWS/JWE {@code kid} 
514                 * header parameter value.
515                 *
516                 * @param kid The key ID, {@code null} if not specified.
517                 *
518                 * @return This builder.
519                 */
520                public Builder keyID(final String kid) {
521
522                        this.kid = kid;
523                        return this;
524                }
525
526
527                /**
528                 * Sets the X.509 certificate URL ({@code x5u}) of the JWK.
529                 *
530                 * @param x5u The X.509 certificate URL, {@code null} if not 
531                 *            specified.
532                 *
533                 * @return This builder.
534                 */
535                public Builder x509CertURL(final URL x5u) {
536
537                        this.x5u = x5u;
538                        return this;
539                }
540
541
542                /**
543                 * Sets the X.509 certificate thumbprint ({@code x5t}) of the
544                 * JWK.
545                 *
546                 * @param x5t The X.509 certificate thumbprint, {@code null} if 
547                 *            not specified.
548                 *
549                 * @return This builder.
550                 */
551                public Builder x509CertThumbprint(final Base64URL x5t) {
552
553                        this.x5t = x5t;
554                        return this;
555                }
556
557
558                /**
559                 * Sets the X.509 certificate chain ({@code x5c}) of the JWK.
560                 *
561                 * @param x5c The X.509 certificate chain as a unmodifiable 
562                 *            list, {@code null} if not specified.
563                 *
564                 * @return This builder.
565                 */
566                public Builder x509CertChain(final List<Base64> x5c) {
567
568                        this.x5c = x5c;
569                        return this;
570                }
571
572
573                /**
574                 * Builds a new octet sequence JWK.
575                 *
576                 * @return The octet sequence JWK.
577                 *
578                 * @throws IllegalStateException If the JWK parameters were
579                 *                               inconsistently specified.
580                 */
581                public ECKey build() {
582
583                        try {
584                                if (d == null) {
585                                        // Public key
586                                        return new ECKey(crv, x, y, use, ops, alg, kid, x5u, x5t, x5c);
587                                }
588
589                                // Pair
590                                return new ECKey(crv, x, y, d, use, ops, alg, kid, x5u, x5t, x5c);
591
592                        } catch (IllegalArgumentException e) {
593
594                                throw new IllegalStateException(e.getMessage(), e);
595                        }
596                }
597        }
598
599
600        /**
601         * Returns the Base64URL encoding of the specified elliptic curve 'x',
602         * 'y' or 'd' coordinate, with leading zero padding up to the specified
603         * field size in bits.
604         *
605         * @param fieldSize  The field size in bits.
606         * @param coordinate The elliptic curve coordinate. Must not be
607         *                   {@code null}.
608         *
609         * @return The Base64URL-encoded coordinate, with leading zero padding
610         *         up to the curve's field size.
611         */
612        public static Base64URL encodeCoordinate(final int fieldSize, final BigInteger coordinate) {
613
614                byte[] unpadded = BigIntegerUtils.toBytesUnsigned(coordinate);
615
616                int bytesToOutput = (fieldSize + 7)/8;
617
618                if (unpadded.length >= bytesToOutput) {
619                        // Greater-than check to prevent exception on malformed
620                        // key below
621                        return Base64URL.encode(unpadded);
622                }
623
624                byte[] padded = new byte[bytesToOutput];
625
626                System.arraycopy(unpadded, 0, padded, bytesToOutput - unpadded.length, unpadded.length);
627
628                return Base64URL.encode(padded);
629        }
630
631
632        /**
633         * The curve name.
634         */
635        private final Curve crv;
636
637
638        /**
639         * The public 'x' EC coordinate.
640         */
641        private final Base64URL x;
642
643
644        /**
645         * The public 'y' EC coordinate.
646         */
647        private final Base64URL y;
648        
649
650        /**
651         * The private 'd' EC coordinate
652         */
653        private final Base64URL d;
654
655
656        /**
657         * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 
658         * specified parameters.
659         *
660         * @param crv The cryptographic curve. Must not be {@code null}.
661         * @param x   The public 'x' coordinate for the elliptic curve point.
662         *            It is represented as the Base64URL encoding of the 
663         *            coordinate's big endian representation. Must not be 
664         *            {@code null}.
665         * @param y   The public 'y' coordinate for the elliptic curve point. 
666         *            It is represented as the Base64URL encoding of the 
667         *            coordinate's big endian representation. Must not be 
668         *            {@code null}.
669         * @param use The public key use, {@code null} if not specified or if
670         *            the key is intended for signing as well as encryption.
671         * @param ops The key operations, {@code null} if not specified.
672         * @param alg The intended JOSE algorithm for the key, {@code null} if
673         *            not specified.
674         * @param kid The key ID, {@code null} if not specified.
675         * @param x5u The X.509 certificate URL, {@code null} if not specified.
676         * @param x5t The X.509 certificate thumbprint, {@code null} if not
677         *            specified.
678         * @param x5c The X.509 certificate chain, {@code null} if not 
679         *            specified.
680         */
681        public ECKey(final Curve crv, final Base64URL x, final Base64URL y, 
682                     final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
683                     final URL x5u, final Base64URL x5t, final List<Base64> x5c) {
684
685                super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5c);
686
687                if (crv == null) {
688                        throw new IllegalArgumentException("The curve must not be null");
689                }
690
691                this.crv = crv;
692
693                if (x == null) {
694                        throw new IllegalArgumentException("The 'x' coordinate must not be null");
695                }
696
697                this.x = x;
698
699                if (y == null) {
700                        throw new IllegalArgumentException("The 'y' coordinate must not be null");
701                }
702
703                this.y = y;
704
705                this.d = null;
706        }
707
708
709        /**
710         * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 
711         * with the specified parameters.
712         *
713         * @param crv The cryptographic curve. Must not be {@code null}.
714         * @param x   The public 'x' coordinate for the elliptic curve point.
715         *            It is represented as the Base64URL encoding of the 
716         *            coordinate's big endian representation. Must not be 
717         *            {@code null}.
718         * @param y   The public 'y' coordinate for the elliptic curve point. 
719         *            It is represented as the Base64URL encoding of the 
720         *            coordinate's big endian representation. Must not be 
721         *            {@code null}.
722         * @param d   The private 'd' coordinate for the elliptic curve point. 
723         *            It is represented as the Base64URL encoding of the 
724         *            coordinate's big endian representation. Must not be 
725         *            {@code null}.
726         * @param use The public key use, {@code null} if not specified or if
727         *            the key is intended for signing as well as encryption.
728         * @param ops The key operations, {@code null} if not specified.
729         * @param alg The intended JOSE algorithm for the key, {@code null} if
730         *            not specified.
731         * @param kid The key ID, {@code null} if not specified.
732         * @param x5u The X.509 certificate URL, {@code null} if not specified.
733         * @param x5t The X.509 certificate thumbprint, {@code null} if not
734         *            specified.
735         * @param x5c The X.509 certificate chain, {@code null} if not 
736         *            specified.
737         */
738        public ECKey(final Curve crv, final Base64URL x, final Base64URL y, final Base64URL d,
739                     final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
740                     final URL x5u, final Base64URL x5t, final List<Base64> x5c) {
741
742                super(KeyType.EC, use, ops, alg, kid, x5u, x5t, x5c);
743
744                if (crv == null) {
745                        throw new IllegalArgumentException("The curve must not be null");
746                }
747
748                this.crv = crv;
749
750                if (x == null) {
751                        throw new IllegalArgumentException("The 'x' coordinate must not be null");
752                }
753
754                this.x = x;
755
756                if (y == null) {
757                        throw new IllegalArgumentException("The 'y' coordinate must not be null");
758                }
759
760                this.y = y;
761                
762                if (d == null) {
763                        throw new IllegalArgumentException("The 'd' coordinate must not be null");
764                }
765
766                this.d = d;
767        }
768
769
770        /**
771         * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 
772         * specified parameters.
773         *
774         * @param crv The cryptographic curve. Must not be {@code null}.
775         * @param pub The public EC key to represent. Must not be {@code null}.
776         * @param use The public key use, {@code null} if not specified or if
777         *            the key is intended for signing as well as encryption.
778         * @param ops The key operations, {@code null} if not specified.
779         * @param alg The intended JOSE algorithm for the key, {@code null} if
780         *            not specified.
781         * @param kid The key ID, {@code null} if not specified.
782         * @param x5u The X.509 certificate URL, {@code null} if not specified.
783         * @param x5t The X.509 certificate thumbprint, {@code null} if not
784         *            specified.
785         * @param x5c The X.509 certificate chain, {@code null} if not 
786         *            specified.
787         */
788        public ECKey(final Curve crv, final ECPublicKey pub, 
789                     final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
790                     final URL x5u, final Base64URL x5t, final List<Base64> x5c) {
791
792                this(crv, 
793                     encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()),
794                     encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()),
795                     use, ops, alg, kid,
796                     x5u, x5t, x5c);
797        }
798
799
800        /**
801         * Creates a new public / private Elliptic Curve JSON Web Key (JWK) 
802         * with the specified parameters.
803         *
804         * @param crv  The cryptographic curve. Must not be {@code null}.
805         * @param pub  The public EC key to represent. Must not be 
806         *             {@code null}.
807         * @param priv The private EC key to represent. Must not be 
808         *             {@code null}.
809         * @param use  The public key use, {@code null} if not specified or if
810         *             the key is intended for signing as well as encryption.
811         * @param ops  The key operations, {@code null} if not specified.
812         * @param alg  The intended JOSE algorithm for the key, {@code null} if
813         *             not specified.
814         * @param kid  The key ID, {@code null} if not specified.
815         * @param x5u  The X.509 certificate URL, {@code null} if not 
816         *             specified.
817         * @param x5t  The X.509 certificate thumbprint, {@code null} if not
818         *             specified.
819         * @param x5c  The X.509 certificate chain, {@code null} if not 
820         *             specified.
821         */
822        public ECKey(final Curve crv, final ECPublicKey pub, final ECPrivateKey priv, 
823                     final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
824                     final URL x5u, final Base64URL x5t, final List<Base64> x5c) {
825
826                this(crv,
827                     encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineX()),
828                     encodeCoordinate(pub.getParams().getCurve().getField().getFieldSize(), pub.getW().getAffineY()),
829                     encodeCoordinate(priv.getParams().getCurve().getField().getFieldSize(), priv.getS()),
830                     use, ops, alg, kid,
831                     x5u, x5t, x5c);
832        }
833
834
835        /**
836         * Gets the cryptographic curve.
837         *
838         * @return The cryptographic curve.
839         */
840        public Curve getCurve() {
841
842                return crv;
843        }
844
845
846        /**
847         * Gets the public 'x' coordinate for the elliptic curve point.
848         *
849         * @return The 'x' coordinate. It is represented as the Base64URL 
850         *         encoding of the coordinate's big endian representation.
851         */
852        public Base64URL getX() {
853
854                return x;
855        }
856
857
858        /**
859         * Gets the public 'y' coordinate for the elliptic curve point.
860         *
861         * @return The 'y' coordinate. It is represented as the Base64URL 
862         *         encoding of the coordinate's big endian representation.
863         */
864        public Base64URL getY() {
865
866                return y;
867        }
868
869        
870        /**
871         * Gets the private 'd' coordinate for the elliptic curve point. It is 
872         * represented as the Base64URL encoding of the coordinate's big endian 
873         * representation.
874         *
875         * @return The 'd' coordinate.  It is represented as the Base64URL 
876         *         encoding of the coordinate's big endian representation. 
877         *         {@code null} if not specified (for a public key).
878         */
879        public Base64URL getD() {
880
881                return d;
882        }
883
884
885        /**
886         * Gets a new BouncyCastle.org EC key factory.
887         *
888         * @return The EC key factory.
889         *
890         * @throws NoSuchAlgorithmException If a JCA provider or algorithm 
891         *                                  exception was encountered.
892         */
893        private static KeyFactory getECKeyFactory()
894                throws NoSuchAlgorithmException {
895
896                return KeyFactory.getInstance("EC", BouncyCastleProviderSingleton.getInstance());
897        }
898
899
900        /**
901         * Returns a standard {@code java.security.interfaces.ECPublicKey} 
902         * representation of this Elliptic Curve JWK.
903         * 
904         * @return The public Elliptic Curve key.
905         * 
906         * @throws NoSuchAlgorithmException If EC is not supported by the
907         *                                  underlying Java Cryptography (JCA)
908         *                                  provider.
909         * @throws InvalidKeySpecException  If the JWK key parameters are 
910         *                                  invalid for a public EC key.
911         */
912        public ECPublicKey toECPublicKey()
913                throws NoSuchAlgorithmException, InvalidKeySpecException {
914
915                ECParameterSpec spec = crv.toECParameterSpec();
916
917                if (spec == null) {
918                        throw new NoSuchAlgorithmException("Couldn't get EC parameter spec for curve " + crv);
919                }
920
921                ECPoint w = new ECPoint(x.decodeToBigInteger(), y.decodeToBigInteger());
922
923                ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(w, spec);
924
925                KeyFactory keyFactory = getECKeyFactory();
926
927                return (ECPublicKey)keyFactory.generatePublic(publicKeySpec);
928        }
929        
930
931        /**
932         * Returns a standard {@code java.security.interfaces.ECPrivateKey} 
933         * representation of this Elliptic Curve JWK.
934         * 
935         * @return The private Elliptic Curve key, {@code null} if not 
936         *         specified by this JWK.
937         * 
938         * @throws NoSuchAlgorithmException If EC is not supported by the
939         *                                  underlying Java Cryptography (JCA)
940         *                                  provider.
941         * @throws InvalidKeySpecException  If the JWK key parameters are 
942         *                                  invalid for a private EC key.
943         */
944        public ECPrivateKey toECPrivateKey()
945                throws NoSuchAlgorithmException, InvalidKeySpecException {
946
947                if (d == null) {
948                        // No private 'd' param
949                        return null;
950                }
951
952                ECParameterSpec spec = crv.toECParameterSpec();
953
954                if (spec == null) {
955                        throw new NoSuchAlgorithmException("Couldn't get EC parameter spec for curve " + crv);
956                }
957
958                ECPrivateKeySpec privateKeySpec = new ECPrivateKeySpec(d.decodeToBigInteger(), spec);
959
960                KeyFactory keyFactory = getECKeyFactory();
961
962                return (ECPrivateKey)keyFactory.generatePrivate(privateKeySpec);
963        }
964        
965
966        /**
967         * Returns a standard {@code java.security.KeyPair} representation of 
968         * this Elliptic Curve JWK.
969         * 
970         * @return The Elliptic Curve key pair. The private Elliptic Curve key 
971         *         will be {@code null} if not specified.
972         * 
973         * @throws NoSuchAlgorithmException If EC is not supported by the
974         *                                  underlying Java Cryptography (JCA)
975         *                                  provider.
976         * @throws InvalidKeySpecException  If the JWK key parameters are 
977         *                                  invalid for a public and / or 
978         *                                  private EC key.
979         */
980        public KeyPair toKeyPair()
981                throws NoSuchAlgorithmException, InvalidKeySpecException {
982
983                return new KeyPair(toECPublicKey(), toECPrivateKey());          
984        }
985
986
987        @Override
988        public boolean isPrivate() {
989
990                return d != null;
991        }
992
993        
994        /**
995         * Returns a copy of this Elliptic Curve JWK with any private values 
996         * removed.
997         *
998         * @return The copied public Elliptic Curve JWK.
999         */
1000        @Override
1001        public ECKey toPublicJWK() {
1002
1003                return new ECKey(getCurve(), getX(), getY(),
1004                                 getKeyUse(), getKeyOperations(), getAlgorithm(), getKeyID(),
1005                                 getX509CertURL(), getX509CertThumbprint(), getX509CertChain());
1006        }
1007        
1008
1009        @Override
1010        public JSONObject toJSONObject() {
1011
1012                JSONObject o = super.toJSONObject();
1013
1014                // Append EC specific attributes
1015                o.put("crv", crv.toString());
1016                o.put("x", x.toString());
1017                o.put("y", y.toString());
1018
1019                if (d != null) {
1020                        o.put("d", d.toString());
1021                }
1022                
1023                return o;
1024        }
1025
1026
1027        /**
1028         * Parses a public / private Elliptic Curve JWK from the specified JSON
1029         * object string representation.
1030         *
1031         * @param s The JSON object string to parse. Must not be {@code null}.
1032         *
1033         * @return The public / private Elliptic Curve JWK.
1034         *
1035         * @throws ParseException If the string couldn't be parsed to an
1036         *                        Elliptic Curve JWK.
1037         */
1038        public static ECKey parse(final String s)
1039                throws ParseException {
1040
1041                return parse(JSONObjectUtils.parseJSONObject(s));
1042        }
1043
1044
1045        /**
1046         * Parses a public / private Elliptic Curve JWK from the specified JSON
1047         * object representation.
1048         *
1049         * @param jsonObject The JSON object to parse. Must not be 
1050         *                   {@code null}.
1051         *
1052         * @return The public / private Elliptic Curve JWK.
1053         *
1054         * @throws ParseException If the JSON object couldn't be parsed to an 
1055         *                        Elliptic Curve JWK.
1056         */
1057        public static ECKey parse(final JSONObject jsonObject)
1058                throws ParseException {
1059
1060                // Parse the mandatory parameters first
1061                Curve crv = Curve.parse(JSONObjectUtils.getString(jsonObject, "crv"));
1062                Base64URL x = new Base64URL(JSONObjectUtils.getString(jsonObject, "x"));
1063                Base64URL y = new Base64URL(JSONObjectUtils.getString(jsonObject, "y"));
1064
1065                // Check key type
1066                KeyType kty = KeyType.parse(JSONObjectUtils.getString(jsonObject, "kty"));
1067
1068                if (kty != KeyType.EC) {
1069                        throw new ParseException("The key type \"kty\" must be EC", 0);
1070                }
1071                
1072                // Get optional private key
1073                Base64URL d = null;
1074                if (jsonObject.get("d") != null) {
1075                        d = new Base64URL(JSONObjectUtils.getString(jsonObject, "d"));
1076                }
1077                
1078                // Get optional key use
1079                KeyUse use = null;
1080
1081                if (jsonObject.containsKey("use")) {
1082                        use = KeyUse.parse(JSONObjectUtils.getString(jsonObject, "use"));
1083                }
1084
1085                // Get optional key operations
1086                Set<KeyOperation> ops = null;
1087
1088                if (jsonObject.containsKey("key_ops")) {
1089                        ops = KeyOperation.parse(JSONObjectUtils.getStringList(jsonObject, "key_ops"));
1090                }
1091
1092                // Get optional intended algorithm
1093                Algorithm alg = null;
1094
1095                if (jsonObject.containsKey("alg")) {
1096                        alg = new Algorithm(JSONObjectUtils.getString(jsonObject, "alg"));
1097                }
1098
1099                // Get optional key ID
1100                String kid = null;
1101
1102                if (jsonObject.containsKey("kid")) {
1103                        kid = JSONObjectUtils.getString(jsonObject, "kid");
1104                }
1105
1106                // Get optional X.509 cert URL
1107                URL x5u = null;
1108
1109                if (jsonObject.containsKey("x5u")) {
1110                        x5u = JSONObjectUtils.getURL(jsonObject, "x5u");        
1111                }
1112
1113                // Get optional X.509 cert thumbprint
1114                Base64URL x5t = null;
1115
1116                if (jsonObject.containsKey("x5t")) {
1117                        x5t = new Base64URL(JSONObjectUtils.getString(jsonObject, "x5t"));
1118                }
1119
1120                // Get optional X.509 cert chain
1121                List<Base64> x5c = null;
1122
1123                if (jsonObject.containsKey("x5c")) {
1124                        x5c = X509CertChainUtils.parseX509CertChain(JSONObjectUtils.getJSONArray(jsonObject, "x5c"));   
1125                }
1126
1127                try {
1128                        if (d == null) {
1129                                // Public key
1130                                return new ECKey(crv, x, y, use, ops, alg, kid, x5u, x5t, x5c);
1131
1132                        } else {
1133                                // Key pair
1134                                return new ECKey(crv, x, y, d, use, ops, alg, kid, x5u, x5t, x5c);
1135                        }
1136
1137                } catch (IllegalArgumentException ex) {
1138
1139                        // Conflicting 'use' and 'key_ops'
1140                        throw new ParseException(ex.getMessage(), 0);
1141                }
1142        }
1143}