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