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