001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyrighted [year] [name of copyright owner]".
013 *
014 * Copyright 2013-2015 ForgeRock AS.
015 */
016
017package org.forgerock.json.jose.jwk;
018
019import java.security.KeyPair;
020import java.security.interfaces.ECPrivateKey;
021import java.security.interfaces.ECPublicKey;
022import java.util.List;
023
024import org.forgerock.json.JsonException;
025import org.forgerock.json.JsonValue;
026import org.forgerock.util.encode.Base64;
027
028/**
029 * This class implements an Elliptical Curve Json Web Key storage and manipulation class.
030 */
031public class EcJWK extends JWK {
032    /**
033     * The X value for the EC point.
034     */
035    private final static String X = "x";
036
037    /**
038     * The Y value for the EC Point.
039     */
040    private final static String Y = "y";
041
042    /**
043     * The private key value.
044     */
045    private final static String D = "d";
046
047    /**
048     * The Curve of the ECC.
049     */
050    private final static String CURVE = "crv";
051
052    /**
053     * Creates a public and private EcJWK.
054     * @param use The value of the use JWK parameter
055     * @param alg The value of the alg JWK parameter
056     * @param kid The key id of the JWK
057     * @param x The x value for the elliptical curve point
058     * @param y The y value for the elliptical curve point
059     * @param d The d value for the elliptical curve private key
060     * @param curve The known curve to use. For example "NIST P-256".
061     * @param x5u the x509 url for the key
062     * @param x5t the x509 thumbnail for the key
063     * @param x5c the x509 chain
064     */
065    public EcJWK(KeyUse use, String alg, String kid, String x, String y, String d, String curve,
066                 String x5u, String x5t, List<Base64> x5c) {
067        super(KeyType.EC, use, alg, kid, x5u, x5t, x5c);
068        if (x == null || x.isEmpty()) {
069            throw new JsonException("x is required for an EcJWK");
070        }
071        put(X, x);
072
073        if (y == null || y.isEmpty()) {
074            throw new JsonException("y is required for an EcJWK");
075        }
076        put(Y, y);
077
078        if (curve == null || curve.isEmpty()) {
079            throw new JsonException("curve is required for an EcJWK");
080        }
081        put(CURVE, curve);
082
083        put(D, d);
084    }
085
086    /**
087     * Creates a public EcJWK.
088     * @param use The value of the use JWK parameter
089     * @param alg The value of the alg JWK parameter
090     * @param kid The key id of the JWK
091     * @param x The x value for the elliptical curve point
092     * @param y The y value for the elliptical curve point
093     * @param curve The known curve to use. For example "NIST P-256".
094     * @param x5u the x509 url for the key
095     * @param x5t the x509 thumbnail for the key
096     * @param x5c the x509 chain
097     */
098    public EcJWK(KeyUse use, String alg, String kid, String x, String y, String curve, String x5u, String x5t,
099                 List<Base64> x5c) {
100        this (use, alg, kid, x, y, null, curve, x5u, x5t, x5c);
101    }
102
103    /**
104     * Gets the x value for the elliptical curve point.
105     * @return x value for the elliptical curve point
106     */
107    public String getX() {
108        return get(X).asString();
109    }
110
111    /**
112     * Gets the y value for the elliptical curve point.
113     * @return y value for the elliptical curve point
114     */
115    public String getY() {
116        return get(Y).asString();
117    }
118
119    /**
120     * Gets the d value for the elliptical curve private key.
121     * @return d value for the elliptical curve point
122     */
123    public String getD() {
124        return get(D).asString();
125    }
126
127    /**
128     * Gets the known curve to use. For example "NIST P-256".
129     * @return the known curve of the JWK
130     */
131    public String getCurve() {
132        return get(CURVE).asString();
133    }
134
135    /**
136     * Parses a JWK from a string json object.
137     * @param json string json object
138     * @return a EcJWK object
139     */
140    public static EcJWK parse(String json) {
141        JsonValue jwk = new JsonValue(toJsonValue(json));
142        return parse(jwk);
143    }
144
145    /**
146     * Parses a JWK from a JsonValue json object.
147     * @param json JsonValue json object
148     * @return a EcJWK object
149     */
150    public static EcJWK parse(JsonValue json) {
151        if (json == null) {
152            throw new JsonException("Cant parse OctJWK. No json data.");
153        }
154
155        KeyType kty = null;
156        KeyUse use = null;
157        String x = null, y = null, d = null, curve = null, alg = null, kid = null;
158        String x5u = null, x5t = null;
159        List<Base64> x5c = null;
160
161        kty = KeyType.getKeyType(json.get(KTY).asString());
162
163        if (!kty.equals(KeyType.EC)) {
164            throw new JsonException("Invalid key type. Not an EC JWK");
165        }
166
167        x = json.get(X).asString();
168        y = json.get(Y).asString();
169        d = json.get(D).asString();
170        curve = json.get(CURVE).asString();
171
172        use = KeyUse.getKeyUse(json.get(USE).asString());
173        alg = json.get(ALG).asString();
174        kid = json.get(KID).asString();
175
176        x5u = json.get(X5U).asString();
177        x5t = json.get(X5T).asString();
178        x5c = json.get(X5C).asList(Base64.class);
179
180        return new EcJWK(use, alg, kid, x, y, d, curve, x5u, x5t, x5c);
181    }
182
183    /**
184     * Prints the JWK as a String json object.
185     * @return a json string object
186     */
187    public String toJsonString() {
188        return super.toString();
189    }
190
191    /**
192     * Converts the JWK to a ECPublicKey.
193     * @return an ECPublicKey
194     */
195    public ECPublicKey toECPublicKey() {
196        /*
197        try {
198            ECParameterSpec spec = NamedCurve.getECParameterSpec(getCurve());
199            ECPoint point = new ECPoint(new BigInteger(Base64url.decode(getX())),
200                                        new BigInteger(Base64url.decode(getY())));
201            ECPublicKeySpec pubspec = new ECPublicKeySpec(point, spec);
202            ECPublicKey pub = (ECPublicKey) ECKeyFactory.INSTANCE.generatePublic(pubspec);
203            return pub;
204        } catch (Exception e) {
205            throw new JsonException("Unable to create public EC key.", e);
206        }
207        */
208        throw new UnsupportedOperationException();
209    }
210
211    /**
212     * Converts the JWK to a ECPrivateKey.
213     * @return an ECPrivateKey
214     */
215    public ECPrivateKey toECPrivateKey() {
216        /*
217        try {
218            ECParameterSpec spec = NamedCurve.getECParameterSpec(getCurve());
219            ECPrivateKeySpec privspec = new ECPrivateKeySpec(new BigInteger(Base64url.decode(getD())), spec);
220            ECPrivateKey priv = (ECPrivateKey) ECKeyFactory.INSTANCE.generatePrivate(privspec);
221            return priv;
222        } catch (Exception e) {
223            throw new JsonException("Unable to create private EC key.", e);
224        }
225        */
226        throw new UnsupportedOperationException();
227    }
228
229    /**
230     * Converts the JWK to a KeyPair.
231     * @return an KeyPair
232     */
233    public KeyPair toKeyPair() {
234        return new KeyPair(toECPublicKey(), toECPrivateKey());
235    }
236}