001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2024, Connect2id Ltd and contributors.
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 com.nimbusds.jose.Algorithm;
022import com.nimbusds.jose.JOSEException;
023import com.nimbusds.jose.util.Base64;
024import com.nimbusds.jose.util.Base64URL;
025import com.nimbusds.jose.util.ByteUtils;
026import com.nimbusds.jose.util.JSONObjectUtils;
027import net.jcip.annotations.Immutable;
028
029import java.net.URI;
030import java.security.KeyPair;
031import java.security.KeyStore;
032import java.security.PrivateKey;
033import java.security.PublicKey;
034import java.security.cert.X509Certificate;
035import java.text.ParseException;
036import java.util.*;
037
038
039/**
040 * {@link KeyType#OKP Octet key pair} JSON Web Key (JWK), used to represent
041 * Edwards-curve keys. This class is immutable.
042 *
043 * <p>Supported curves:
044 *
045 * <ul>
046 *     <li>{@link Curve#Ed25519 Ed25519}
047 *     <li>{@link Curve#Ed448 Ed448}
048 *     <li>{@link Curve#X25519 X25519}
049 *     <li>{@link Curve#X448 X448}
050 * </ul>
051 *
052 * <p>Example JSON object representation of a public OKP JWK:
053 *
054 * <pre>
055 * {
056 *   "kty" : "OKP",
057 *   "crv" : "Ed25519",
058 *   "x"   : "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
059 *   "use" : "sig",
060 *   "kid" : "1"
061 * }
062 * </pre>
063 *
064 * <p>Example JSON object representation of a private OKP JWK:
065 *
066 * <pre>
067 * {
068 *   "kty" : "OKP",
069 *   "crv" : "Ed25519",
070 *   "x"   : "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo",
071 *   "d"   : "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
072 *   "use" : "sig",
073 *   "kid" : "1"
074 * }
075 * </pre>
076 *
077 * <p>Use the builder to create a new OKP JWK:
078 *
079 * <pre>
080 * OctetKeyPair key = new OctetKeyPair.Builder(Curve.Ed25519, x)
081 *      .keyUse(KeyUse.SIGNATURE)
082 *      .keyID("1")
083 *      .build();
084 * </pre>
085 *
086 * @author Vladimir Dzhuvinov
087 * @version 2024-04-27
088 */
089@Immutable
090public class OctetKeyPair extends JWK implements AsymmetricJWK, CurveBasedJWK {
091        
092        
093        private static final long serialVersionUID = 1L;
094        
095        
096        /**
097         * Supported Edwards curves.
098         */
099        public static final Set<Curve> SUPPORTED_CURVES = Collections.unmodifiableSet(
100                new HashSet<>(Arrays.asList(Curve.Ed25519, Curve.Ed448, Curve.X25519, Curve.X448))
101        );
102        
103        
104        /**
105         * Builder for constructing Octet Key Pair JWKs.
106         *
107         * <p>Example usage:
108         *
109         * <pre>
110         * OctetKeyPair key = new OctetKeyPair.Builder(Curve.Ed25519, x)
111         *     .d(d)
112         *     .algorithm(JWSAlgorithm.EdDSA)
113         *     .keyID("1")
114         *     .build();
115         * </pre>
116         */
117        public static class Builder {
118                
119                
120                /**
121                 * The curve name.
122                 */
123                private final Curve crv;
124                
125                
126                /**
127                 * The public 'x' parameter.
128                 */
129                private final Base64URL x;
130                
131                
132                /**
133                 * The private 'd' parameter, optional.
134                 */
135                private Base64URL d;
136                
137                
138                /**
139                 * The key use, optional.
140                 */
141                private KeyUse use;
142                
143                
144                /**
145                 * The key operations, optional.
146                 */
147                private Set<KeyOperation> ops;
148                
149                
150                /**
151                 * The intended JOSE algorithm for the key, optional.
152                 */
153                private Algorithm alg;
154                
155                
156                /**
157                 * The key ID, optional.
158                 */
159                private String kid;
160                
161                
162                /**
163                 * X.509 certificate URL, optional.
164                 */
165                private URI x5u;
166                
167                
168                /**
169                 * X.509 certificate SHA-1 thumbprint, optional.
170                 */
171                @Deprecated
172                private Base64URL x5t;
173                
174                
175                /**
176                 * X.509 certificate SHA-256 thumbprint, optional.
177                 */
178                private Base64URL x5t256;
179                
180                
181                /**
182                 * The X.509 certificate chain, optional.
183                 */
184                private List<Base64> x5c;
185                
186                
187                /**
188                 * The key expiration time, optional.
189                 */
190                private Date exp;
191                
192                
193                /**
194                 * The key not-before time, optional.
195                 */
196                private Date nbf;
197                
198                
199                /**
200                 * The key issued-at time, optional.
201                 */
202                private Date iat;
203
204
205                /**
206                 * The key revocation, optional.
207                 */
208                private KeyRevocation revocation;
209                
210                
211                /**
212                 * Reference to the underlying key store, {@code null} if none.
213                 */
214                private KeyStore ks;
215                
216                
217                /**
218                 * Creates a new Octet Key Pair JWK builder.
219                 *
220                 * @param crv The cryptographic curve. Must not be
221                 *            {@code null}.
222                 * @param x   The public 'x' parameter. Must not be 
223                 *            {@code null}.
224                 */
225                public Builder(final Curve crv, final Base64URL x) {
226                        
227                        this.crv = Objects.requireNonNull(crv, "The curve must not be null");
228                        this.x = Objects.requireNonNull(x, "The x coordinate must not be null");
229                }
230                
231                
232                /**
233                 * Creates a new Octet Key Pair JWK builder.
234                 *
235                 * @param okpJWK The Octet Key Pair to start with. Must not be
236                 *              {@code null}.
237                 */
238                public Builder(final OctetKeyPair okpJWK) {
239                        
240                        crv = okpJWK.crv;
241                        x = okpJWK.x;
242                        d = okpJWK.d;
243                        use = okpJWK.getKeyUse();
244                        ops = okpJWK.getKeyOperations();
245                        alg = okpJWK.getAlgorithm();
246                        kid = okpJWK.getKeyID();
247                        x5u = okpJWK.getX509CertURL();
248                        x5t = okpJWK.getX509CertThumbprint();
249                        x5t256 = okpJWK.getX509CertSHA256Thumbprint();
250                        x5c = okpJWK.getX509CertChain();
251                        exp = okpJWK.getExpirationTime();
252                        nbf = okpJWK.getNotBeforeTime();
253                        iat = okpJWK.getIssueTime();
254                        revocation = okpJWK.getKeyRevocation();
255                        ks = okpJWK.getKeyStore();
256                }
257                
258                
259                /**
260                 * Sets the private 'd' parameter.
261                 *
262                 * @param d The private 'd' parameter, {@code null} if not 
263                 *          specified (for a public key).
264                 *
265                 * @return This builder.
266                 */
267                public Builder d(final Base64URL d) {
268                        
269                        this.d = d;
270                        return this;
271                }
272                
273                
274                /**
275                 * Sets the use ({@code use}) of the JWK.
276                 *
277                 * @param use The key use, {@code null} if not specified or if
278                 *            the key is intended for signing as well as
279                 *            encryption.
280                 *
281                 * @return This builder.
282                 */
283                public Builder keyUse(final KeyUse use) {
284                        
285                        this.use = use;
286                        return this;
287                }
288                
289                
290                /**
291                 * Sets the operations ({@code key_ops}) of the JWK.
292                 *
293                 * @param ops The key operations, {@code null} if not
294                 *            specified.
295                 *
296                 * @return This builder.
297                 */
298                public Builder keyOperations(final Set<KeyOperation> ops) {
299                        
300                        this.ops = ops;
301                        return this;
302                }
303                
304                
305                /**
306                 * Sets the intended JOSE algorithm ({@code alg}) for the JWK.
307                 *
308                 * @param alg The intended JOSE algorithm, {@code null} if not
309                 *            specified.
310                 *
311                 * @return This builder.
312                 */
313                public Builder algorithm(final Algorithm alg) {
314                        
315                        this.alg = alg;
316                        return this;
317                }
318                
319                /**
320                 * Sets the ID ({@code kid}) of the JWK. The key ID can be used
321                 * to match a specific key. This can be used, for instance, to
322                 * choose a key within a {@link JWKSet} during key rollover.
323                 * The key ID may also correspond to a JWS/JWE {@code kid}
324                 * header parameter value.
325                 *
326                 * @param kid The key ID, {@code null} if not specified.
327                 *
328                 * @return This builder.
329                 */
330                public Builder keyID(final String kid) {
331                        
332                        this.kid = kid;
333                        return this;
334                }
335                
336                
337                /**
338                 * Sets the ID ({@code kid}) of the JWK to its SHA-256 JWK
339                 * thumbprint (RFC 7638). The key ID can be used to match a
340                 * specific key. This can be used, for instance, to choose a
341                 * key within a {@link JWKSet} during key rollover. The key ID
342                 * may also correspond to a JWS/JWE {@code kid} header
343                 * parameter value.
344                 *
345                 * @return This builder.
346                 *
347                 * @throws JOSEException If the SHA-256 hash algorithm is not
348                 *                       supported.
349                 */
350                public Builder keyIDFromThumbprint()
351                        throws JOSEException {
352                        
353                        return keyIDFromThumbprint("SHA-256");
354                }
355                
356                
357                /**
358                 * Sets the ID ({@code kid}) of the JWK to its JWK thumbprint
359                 * (RFC 7638). The key ID can be used to match a specific key.
360                 * This can be used, for instance, to choose a key within a
361                 * {@link JWKSet} during key rollover. The key ID may also
362                 * correspond to a JWS/JWE {@code kid} header parameter value.
363                 *
364                 * @param hashAlg The hash algorithm for the JWK thumbprint
365                 *                computation. Must not be {@code null}.
366                 *
367                 * @return This builder.
368                 *
369                 * @throws JOSEException If the hash algorithm is not
370                 *                       supported.
371                 */
372                public Builder keyIDFromThumbprint(final String hashAlg)
373                        throws JOSEException {
374                        
375                        // Put mandatory params in sorted order
376                        LinkedHashMap<String,String> requiredParams = new LinkedHashMap<>();
377                        requiredParams.put(JWKParameterNames.OKP_SUBTYPE, crv.toString());
378                        requiredParams.put(JWKParameterNames.KEY_TYPE, KeyType.OKP.getValue());
379                        requiredParams.put(JWKParameterNames.OKP_PUBLIC_KEY, x.toString());
380                        this.kid = ThumbprintUtils.compute(hashAlg, requiredParams).toString();
381                        return this;
382                }
383                
384                
385                /**
386                 * Sets the X.509 certificate URL ({@code x5u}) of the JWK.
387                 *
388                 * @param x5u The X.509 certificate URL, {@code null} if not
389                 *            specified.
390                 *
391                 * @return This builder.
392                 */
393                public Builder x509CertURL(final URI x5u) {
394                        
395                        this.x5u = x5u;
396                        return this;
397                }
398                
399                
400                /**
401                 * Sets the X.509 certificate SHA-1 thumbprint ({@code x5t}) of
402                 * the JWK.
403                 *
404                 * @param x5t The X.509 certificate SHA-1 thumbprint,
405                 *            {@code null} if not specified.
406                 *
407                 * @return This builder.
408                 */
409                @Deprecated
410                public Builder x509CertThumbprint(final Base64URL x5t) {
411                        
412                        this.x5t = x5t;
413                        return this;
414                }
415                
416                
417                /**
418                 * Sets the X.509 certificate SHA-256 thumbprint
419                 * ({@code x5t#S256}) of the JWK.
420                 *
421                 * @param x5t256 The X.509 certificate SHA-256 thumbprint,
422                 *               {@code null} if not specified.
423                 *
424                 * @return This builder.
425                 */
426                public Builder x509CertSHA256Thumbprint(final Base64URL x5t256) {
427                        
428                        this.x5t256 = x5t256;
429                        return this;
430                }
431                
432                
433                /**
434                 * Sets the X.509 certificate chain ({@code x5c}) of the JWK.
435                 *
436                 * @param x5c The X.509 certificate chain as a unmodifiable
437                 *            list, {@code null} if not specified.
438                 *
439                 * @return This builder.
440                 */
441                public Builder x509CertChain(final List<Base64> x5c) {
442                        
443                        this.x5c = x5c;
444                        return this;
445                }
446                
447                
448                /**
449                 * Sets the expiration time ({@code exp}) of the JWK.
450                 *
451                 * @param exp The expiration time, {@code null} if not
452                 *            specified.
453                 *
454                 * @return This builder.
455                 */
456                public Builder expirationTime(final Date exp) {
457                        
458                        this.exp = exp;
459                        return this;
460                }
461                
462                
463                /**
464                 * Sets the not-before time ({@code nbf}) of the JWK.
465                 *
466                 * @param nbf The not-before time, {@code null} if not
467                 *            specified.
468                 *
469                 * @return This builder.
470                 */
471                public Builder notBeforeTime(final Date nbf) {
472                        
473                        this.nbf = nbf;
474                        return this;
475                }
476                
477                
478                /**
479                 * Sets the issued-at time ({@code iat}) of the JWK.
480                 *
481                 * @param iat The issued-at time, {@code null} if not
482                 *            specified.
483                 *
484                 * @return This builder.
485                 */
486                public Builder issueTime(final Date iat) {
487                        
488                        this.iat = iat;
489                        return this;
490                }
491
492
493                /**
494                 * Sets the revocation ({@code revoked}) of the JWK.
495                 *
496                 * @param revocation The key revocation, {@code null} if not
497                 *                   specified.
498                 *
499                 * @return This builder.
500                 */
501                public Builder keyRevocation(final KeyRevocation revocation) {
502
503                        this.revocation = revocation;
504                        return this;
505                }
506                
507                
508                /**
509                 * Sets the underlying key store.
510                 *
511                 * @param keyStore Reference to the underlying key store,
512                 *                 {@code null} if none.
513                 *
514                 * @return This builder.
515                 */
516                public Builder keyStore(final KeyStore keyStore) {
517                        
518                        this.ks = keyStore;
519                        return this;
520                }
521                
522                
523                /**
524                 * Builds a new Octet Key Pair JWK.
525                 *
526                 * @return The Octet Key Pair JWK.
527                 *
528                 * @throws IllegalStateException If the JWK parameters were
529                 *                               inconsistently specified.
530                 */
531                public OctetKeyPair build() {
532                        
533                        try {
534                                if (d == null) {
535                                        // Public key
536                                        return new OctetKeyPair(crv, x, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, revocation, ks);
537                                }
538                                
539                                // Public / private key pair with 'd'
540                                return new OctetKeyPair(crv, x, d, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, revocation, ks);
541                                
542                        } catch (IllegalArgumentException e) {
543                                throw new IllegalStateException(e.getMessage(), e);
544                        }
545                }
546        }
547        
548        
549        /**
550         * The curve name.
551         */
552        private final Curve crv;
553        
554        
555        /**
556         * The public 'x' parameter.
557         */
558        private final Base64URL x;
559
560
561        /**
562         * The public 'x' parameter, decoded from Base64.
563         * Cached for performance and to reduce the risk of side channel attacks
564         * against the Base64 decoding procedure.
565         */
566        private final byte[] decodedX;
567
568
569        /**
570         * The private 'd' parameter.
571         */
572        private final Base64URL d;
573
574
575        /**
576         * The private 'd' parameter, decoded from Base64.
577         * Cached for performance and to reduce the risk of side channel attacks
578         * against the Base64 decoding procedure.
579         */
580        private final byte[] decodedD;
581
582
583        /**
584         * Creates a new public Octet Key Pair JSON Web Key (JWK) with the
585         * specified parameters.
586         *
587         * @param crv    The cryptographic curve. Must not be {@code null}.
588         * @param x      The public 'x' parameter. Must not be {@code null}.
589         * @param use    The key use, {@code null} if not specified or if the
590         *               key is intended for signing as well as encryption.
591         * @param ops    The key operations, {@code null} if not specified.
592         * @param alg    The intended JOSE algorithm for the key, {@code null}
593         *               if not specified.
594         * @param kid    The key ID, {@code null} if not specified.
595         * @param x5u    The X.509 certificate URL, {@code null} if not
596         *               specified.
597         * @param x5t    The X.509 certificate SHA-1 thumbprint, {@code null}
598         *               if not specified.
599         * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null}
600         *               if not specified.
601         * @param x5c    The X.509 certificate chain, {@code null} if not
602         *               specified.
603         * @param ks     Reference to the underlying key store, {@code null} if
604         *               not specified.
605         */
606        @Deprecated
607        public OctetKeyPair(final Curve crv, final Base64URL x,
608                            final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
609                            final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c,
610                            final KeyStore ks) {
611                
612                this(crv, x, use, ops, alg, kid, x5u, x5t, x5t256, x5c, null, null, null, ks);
613        }
614        
615        
616        /**
617         * Creates a new public / private Octet Key Pair JSON Web Key (JWK)
618         * with the specified parameters.
619         *
620         * @param crv    The cryptographic curve. Must not be {@code null}.
621         * @param x      The public 'x' parameter. Must not be {@code null}.
622         * @param d      The private 'd' parameter. Must not be {@code null}.
623         * @param use    The key use, {@code null} if not specified or if the
624         *               key is intended for signing as well as encryption.
625         * @param ops    The key operations, {@code null} if not specified.
626         * @param alg    The intended JOSE algorithm for the key, {@code null}
627         *               if not specified.
628         * @param kid    The key ID, {@code null} if not specified.
629         * @param x5u    The X.509 certificate URL, {@code null} if not
630         *               specified.
631         * @param x5t    The X.509 certificate SHA-1 thumbprint, {@code null}
632         *               if not specified.
633         * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null}
634         *               if not specified.
635         * @param x5c    The X.509 certificate chain, {@code null} if not
636         *               specified.
637         * @param ks     Reference to the underlying key store, {@code null} if
638         *               not specified.
639         */
640        @Deprecated
641        public OctetKeyPair(final Curve crv, final Base64URL x, final Base64URL d,
642                            final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
643                            final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c,
644                            final KeyStore ks) {
645                
646                this(crv, x, d, use, ops, alg, kid, x5u, x5t, x5t256, x5c, null, null, null, ks);
647        }
648
649
650        /**
651         * Creates a new public Octet Key Pair JSON Web Key (JWK) with the
652         * specified parameters.
653         *
654         * @param crv    The cryptographic curve. Must not be {@code null}.
655         * @param x      The public 'x' parameter. Must not be {@code null}.
656         * @param use    The key use, {@code null} if not specified or if the
657         *               key is intended for signing as well as encryption.
658         * @param ops    The key operations, {@code null} if not specified.
659         * @param alg    The intended JOSE algorithm for the key, {@code null}
660         *               if not specified.
661         * @param kid    The key ID, {@code null} if not specified.
662         * @param x5u    The X.509 certificate URL, {@code null} if not
663         *               specified.
664         * @param x5t    The X.509 certificate SHA-1 thumbprint, {@code null}
665         *               if not specified.
666         * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null}
667         *               if not specified.
668         * @param x5c    The X.509 certificate chain, {@code null} if not
669         *               specified.
670         * @param exp    The key expiration time, {@code null} if not
671         *               specified.
672         * @param nbf    The key not-before time, {@code null} if not
673         *               specified.
674         * @param iat    The key issued-at time, {@code null} if not specified.
675         * @param ks     Reference to the underlying key store, {@code null} if
676         *               not specified.
677         */
678        @Deprecated
679        public OctetKeyPair(final Curve crv, final Base64URL x,
680                            final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
681                            final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c,
682                            final Date exp, final Date nbf, final Date iat,
683                            final KeyStore ks) {
684                
685                this(crv, x, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, null, ks);
686        }
687
688
689        // JWK public
690        /**
691         * Creates a new public Octet Key Pair JSON Web Key (JWK) with the
692         * specified parameters.
693         *
694         * @param crv        The cryptographic curve. Must not be {@code null}.
695         * @param x          The public 'x' parameter. Must not be
696         *                   {@code null}.
697         * @param use        The key use, {@code null} if not specified or if
698         *                   the key is intended for signing as well as
699         *                   encryption.
700         * @param ops        The key operations, {@code null} if not specified.
701         * @param alg        The intended JOSE algorithm for the key,
702         *                   {@code null} if not specified.
703         * @param kid        The key ID, {@code null} if not specified.
704         * @param x5u        The X.509 certificate URL, {@code null} if not
705         *                   specified.
706         * @param x5t        The X.509 certificate SHA-1 thumbprint,
707         *                   {@code null} if not specified.
708         * @param x5t256     The X.509 certificate SHA-256 thumbprint,
709         *                   {@code null} if not specified.
710         * @param x5c        The X.509 certificate chain, {@code null} if not
711         *                   specified.
712         * @param exp        The key expiration time, {@code null} if not
713         *                   specified.
714         * @param nbf        The key not-before time, {@code null} if not
715         *                   specified.
716         * @param iat        The key issued-at time, {@code null} if not
717         *                   specified.
718         * @param revocation The key revocation, {@code null} if not specified.
719         * @param ks         Reference to the underlying key store,
720         *                   {@code null} if not specified.
721         */
722        public OctetKeyPair(final Curve crv, final Base64URL x,
723                            final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
724                            final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c,
725                            final Date exp, final Date nbf, final Date iat, final KeyRevocation revocation,
726                            final KeyStore ks) {
727
728                super(KeyType.OKP, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, revocation, ks);
729
730                Objects.requireNonNull(crv, "The curve must not be null");
731                if (! SUPPORTED_CURVES.contains(crv)) {
732                        throw new IllegalArgumentException("Unknown / unsupported curve: " + crv);
733                }
734
735                this.crv = crv;
736
737                this.x = Objects.requireNonNull(x, "The " + JWKParameterNames.OKP_PUBLIC_KEY + " parameter must not be null");
738                decodedX = x.decode();
739
740                d = null;
741                decodedD = null;
742        }
743        
744        
745        /**
746         * Creates a new public / private Octet Key Pair JSON Web Key (JWK)
747         * with the specified parameters.
748         *
749         * @param crv    The cryptographic curve. Must not be {@code null}.
750         * @param x      The public 'x' parameter. Must not be {@code null}.
751         * @param d      The private 'd' parameter. Must not be {@code null}.
752         * @param use    The key use, {@code null} if not specified or if the
753         *               key is intended for signing as well as encryption.
754         * @param ops    The key operations, {@code null} if not specified.
755         * @param alg    The intended JOSE algorithm for the key, {@code null}
756         *               if not specified.
757         * @param kid    The key ID, {@code null} if not specified.
758         * @param x5u    The X.509 certificate URL, {@code null} if not
759         *               specified.
760         * @param x5t    The X.509 certificate SHA-1 thumbprint, {@code null}
761         *               if not specified.
762         * @param x5t256 The X.509 certificate SHA-256 thumbprint, {@code null}
763         *               if not specified.
764         * @param x5c    The X.509 certificate chain, {@code null} if not
765         *               specified.
766         * @param exp    The key expiration time, {@code null} if not
767         *               specified.
768         * @param nbf    The key not-before time, {@code null} if not
769         *               specified.
770         * @param iat    The key issued-at time, {@code null} if not specified.
771         * @param ks     Reference to the underlying key store, {@code null} if
772         *               not specified.
773         */
774        @Deprecated
775        public OctetKeyPair(final Curve crv, final Base64URL x, final Base64URL d,
776                            final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
777                            final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c,
778                            final Date exp, final Date nbf, final Date iat,
779                            final KeyStore ks) {
780                
781                this(crv, x, d, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, null, ks);
782        }
783
784
785        // JWK public + private
786        /**
787         * Creates a new public / private Octet Key Pair JSON Web Key (JWK)
788         * with the specified parameters.
789         *
790         * @param crv        The cryptographic curve. Must not be {@code null}.
791         * @param x          The public 'x' parameter. Must not be
792         *                   {@code null}.
793         * @param d          The private 'd' parameter. Must not be
794         *                   {@code null}.
795         * @param use        The key use, {@code null} if not specified or if
796         *                   the key is intended for signing as well as
797         *                   encryption.
798         * @param ops        The key operations, {@code null} if not specified.
799         * @param alg        The intended JOSE algorithm for the key,
800         *                   {@code null} if not specified.
801         * @param kid        The key ID, {@code null} if not specified.
802         * @param x5u        The X.509 certificate URL, {@code null} if not
803         *                   specified.
804         * @param x5t        The X.509 certificate SHA-1 thumbprint,
805         *                   {@code null} if not specified.
806         * @param x5t256     The X.509 certificate SHA-256 thumbprint,
807         *                   {@code null} if not specified.
808         * @param x5c        The X.509 certificate chain, {@code null} if not
809         *                   specified.
810         * @param exp        The key expiration time, {@code null} if not
811         *                   specified.
812         * @param nbf        The key not-before time, {@code null} if not
813         *                   specified.
814         * @param iat        The key issued-at time, {@code null} if not
815         *                   specified.
816         * @param revocation The key revocation, {@code null} if not specified.
817         * @param ks         Reference to the underlying key store,
818         *                   {@code null} if not specified.
819         */
820        public OctetKeyPair(final Curve crv, final Base64URL x, final Base64URL d,
821                            final KeyUse use, final Set<KeyOperation> ops, final Algorithm alg, final String kid,
822                            final URI x5u, final Base64URL x5t, final Base64URL x5t256, final List<Base64> x5c,
823                            final Date exp, final Date nbf, final Date iat, final KeyRevocation revocation,
824                            final KeyStore ks) {
825
826                super(KeyType.OKP, use, ops, alg, kid, x5u, x5t, x5t256, x5c, exp, nbf, iat, revocation, ks);
827
828                Objects.requireNonNull(crv, "The curve must not be null");
829                if (! SUPPORTED_CURVES.contains(crv)) {
830                        throw new IllegalArgumentException("Unknown / unsupported curve: " + crv);
831                }
832                this.crv = crv;
833
834                this.x = Objects.requireNonNull(x, "The " + JWKParameterNames.OKP_PUBLIC_KEY + " parameter must not be null");
835                decodedX = x.decode();
836
837                this.d = Objects.requireNonNull(d, "The " + JWKParameterNames.OKP_PRIVATE_KEY + " parameter must not be null");
838                decodedD = d.decode();
839        }
840        
841        
842        @Override
843        public Curve getCurve() {
844                
845                return crv;
846        }
847        
848        
849        /**
850         * Gets the public 'x' parameter.
851         *
852         * @return The public 'x' parameter.
853         */
854        public Base64URL getX() {
855                
856                return x;
857        }
858
859
860        /**
861         * Gets the public 'x' parameter, decoded from Base64.
862         *
863         * @return The public 'x' parameter in bytes.
864         */
865        public byte[] getDecodedX() {
866
867                return decodedX.clone();
868        }
869
870
871        /**
872         * Gets the private 'd' parameter.
873         *
874         * @return The private 'd' coordinate, {@code null} if not specified
875         *         (for a public key).
876         */
877        public Base64URL getD() {
878                
879                return d;
880        }
881
882
883        /**
884         * Gets the private 'd' parameter, decoded from Base64.
885         *
886         * @return The private 'd' coordinate in bytes, {@code null} if not specified
887         *         (for a public key).
888         */
889        public byte[] getDecodedD() {
890
891                return decodedD == null ? null : decodedD.clone();
892        }
893
894
895        @Override
896        public PublicKey toPublicKey()
897                throws JOSEException {
898                
899                throw new JOSEException("Export to java.security.PublicKey not supported");
900        }
901        
902        
903        @Override
904        public PrivateKey toPrivateKey()
905                throws JOSEException {
906                
907                throw new JOSEException("Export to java.security.PrivateKey not supported");
908        }
909        
910        
911        @Override
912        public KeyPair toKeyPair()
913                throws JOSEException {
914                
915                throw new JOSEException("Export to java.security.KeyPair not supported");
916        }
917        
918        
919        @Override
920        public boolean matches(final X509Certificate cert) {
921                // X.509 certs don't support OKP yet
922                return false;
923        }
924        
925        
926        @Override
927        public LinkedHashMap<String,?> getRequiredParams() {
928                
929                // Put mandatory params in sorted order
930                LinkedHashMap<String,String> requiredParams = new LinkedHashMap<>();
931                requiredParams.put(JWKParameterNames.OKP_SUBTYPE, crv.toString());
932                requiredParams.put(JWKParameterNames.KEY_TYPE, getKeyType().getValue());
933                requiredParams.put(JWKParameterNames.OKP_PUBLIC_KEY, x.toString());
934                return requiredParams;
935        }
936        
937        
938        @Override
939        public boolean isPrivate() {
940                
941                return d != null;
942        }
943        
944        
945        /**
946         * Returns a copy of this Octet Key Pair JWK with any private values
947         * removed.
948         *
949         * @return The copied public Octet Key Pair JWK.
950         */
951        @Override
952        public OctetKeyPair toPublicJWK() {
953                
954                return new OctetKeyPair(
955                        getCurve(), getX(),
956                        getKeyUse(), getKeyOperations(), getAlgorithm(), getKeyID(),
957                        getX509CertURL(), getX509CertThumbprint(), getX509CertSHA256Thumbprint(), getX509CertChain(),
958                        getExpirationTime(), getNotBeforeTime(), getIssueTime(), getKeyRevocation(),
959                        getKeyStore());
960        }
961        
962        
963        @Override
964        public Map<String, Object> toJSONObject() {
965                
966                Map<String, Object> o = super.toJSONObject();
967                
968                // Append OKP specific attributes
969                o.put(JWKParameterNames.OKP_SUBTYPE, crv.toString());
970                o.put(JWKParameterNames.OKP_PUBLIC_KEY, x.toString());
971                
972                if (d != null) {
973                        o.put(JWKParameterNames.OKP_PRIVATE_KEY, d.toString());
974                }
975                
976                return o;
977        }
978        
979        
980        @Override
981        public int size() {
982                
983                return ByteUtils.bitLength(x.decode());
984        }
985        
986        
987        /**
988         * Parses a public / private Octet Key Pair JWK from the specified JSON
989         * object string representation.
990         *
991         * @param s The JSON object string to parse. Must not be {@code null}.
992         *
993         * @return The public / private Octet Key Pair JWK.
994         *
995         * @throws ParseException If the string couldn't be parsed to an Octet
996         *                        Key Pair JWK.
997         */
998        public static OctetKeyPair parse(final String s)
999                throws ParseException {
1000                
1001                return parse(JSONObjectUtils.parse(s));
1002        }
1003        
1004        
1005        /**
1006         * Parses a public / private Octet Key Pair JWK from the specified JSON
1007         * object representation.
1008         *
1009         * @param jsonObject The JSON object to parse. Must not be
1010         *                   {@code null}.
1011         *
1012         * @return The public / private Octet Key Pair JWK.
1013         *
1014         * @throws ParseException If the JSON object couldn't be parsed to an
1015         *                        Octet Key Pair JWK.
1016         */
1017        public static OctetKeyPair parse(final Map<String, Object> jsonObject)
1018                throws ParseException {
1019                
1020                // Check the key type
1021                if (! KeyType.OKP.equals(JWKMetadata.parseKeyType(jsonObject))) {
1022                        throw new ParseException("The key type " + JWKParameterNames.KEY_TYPE + " must be " + KeyType.OKP.getValue(), 0);
1023                }
1024                
1025                // Parse the mandatory parameters
1026                Curve crv;
1027                try {
1028                        crv = Curve.parse(JSONObjectUtils.getString(jsonObject, JWKParameterNames.OKP_SUBTYPE));
1029                } catch (IllegalArgumentException e) {
1030                        throw new ParseException(e.getMessage(), 0);
1031                }
1032                
1033                Base64URL x = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.OKP_PUBLIC_KEY);
1034                
1035                // Get the optional private key
1036                Base64URL d = JSONObjectUtils.getBase64URL(jsonObject, JWKParameterNames.OKP_PRIVATE_KEY);
1037                
1038                try {
1039                        if (d == null) {
1040                                // Public key
1041                                return new OctetKeyPair(crv, x,
1042                                        JWKMetadata.parseKeyUse(jsonObject),
1043                                        JWKMetadata.parseKeyOperations(jsonObject),
1044                                        JWKMetadata.parseAlgorithm(jsonObject),
1045                                        JWKMetadata.parseKeyID(jsonObject),
1046                                        JWKMetadata.parseX509CertURL(jsonObject),
1047                                        JWKMetadata.parseX509CertThumbprint(jsonObject),
1048                                        JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject),
1049                                        JWKMetadata.parseX509CertChain(jsonObject),
1050                                        JWKMetadata.parseExpirationTime(jsonObject),
1051                                        JWKMetadata.parseNotBeforeTime(jsonObject),
1052                                        JWKMetadata.parseIssueTime(jsonObject),
1053                                        JWKMetadata.parseKeyRevocation(jsonObject),
1054                                        null);
1055                                
1056                        } else {
1057                                // Key pair
1058                                return new OctetKeyPair(crv, x, d,
1059                                        JWKMetadata.parseKeyUse(jsonObject),
1060                                        JWKMetadata.parseKeyOperations(jsonObject),
1061                                        JWKMetadata.parseAlgorithm(jsonObject),
1062                                        JWKMetadata.parseKeyID(jsonObject),
1063                                        JWKMetadata.parseX509CertURL(jsonObject),
1064                                        JWKMetadata.parseX509CertThumbprint(jsonObject),
1065                                        JWKMetadata.parseX509CertSHA256Thumbprint(jsonObject),
1066                                        JWKMetadata.parseX509CertChain(jsonObject),
1067                                        JWKMetadata.parseExpirationTime(jsonObject),
1068                                        JWKMetadata.parseNotBeforeTime(jsonObject),
1069                                        JWKMetadata.parseIssueTime(jsonObject),
1070                                        JWKMetadata.parseKeyRevocation(jsonObject),
1071                                        null);
1072                        }
1073                        
1074                } catch (Exception ex) {
1075                        
1076                        // Conflicting 'use' and 'key_ops'
1077                        throw new ParseException(ex.getMessage(), 0);
1078                }
1079        }
1080
1081        
1082        @Override
1083        public boolean equals(Object o) {
1084                if (this == o) return true;
1085                if (!(o instanceof OctetKeyPair)) return false;
1086                if (!super.equals(o)) return false;
1087                OctetKeyPair that = (OctetKeyPair) o;
1088                return Objects.equals(crv, that.crv) &&
1089                                Objects.equals(x, that.x) &&
1090                                Arrays.equals(decodedX, that.decodedX) &&
1091                                Objects.equals(d, that.d) &&
1092                                Arrays.equals(decodedD, that.decodedD);
1093        }
1094
1095        
1096        @Override
1097        public int hashCode() {
1098                int result = Objects.hash(super.hashCode(), crv, x, d);
1099                result = 31 * result + Arrays.hashCode(decodedX);
1100                result = 31 * result + Arrays.hashCode(decodedD);
1101                return result;
1102        }
1103}