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