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