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