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