001 package com.nimbusds.jose;
002
003
004 import java.text.ParseException;
005
006 import net.minidev.json.JSONObject;
007
008 import net.jcip.annotations.Immutable;
009
010 import com.nimbusds.jose.util.Base64URL;
011 import com.nimbusds.jose.util.JSONObjectUtils;
012
013
014 /**
015 * Public {@link KeyType#EC Elliptic Curve} JSON Web Key (JWK). This class is
016 * immutable.
017 *
018 * <p>Example JSON:
019 *
020 * <pre>
021 * {
022 * "kty" : "EC",
023 * "crv" : "P-256",
024 * "x" : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
025 * "y" : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
026 * "use" : "enc",
027 * "kid" : "1"
028 * }
029 * </pre>
030 *
031 * <p>See http://en.wikipedia.org/wiki/Elliptic_curve_cryptography
032 *
033 * @author Vladimir Dzhuvinov
034 * @version $version$ (2013-01-15)
035 */
036 @Immutable
037 public final class ECKey extends JWK {
038
039
040 /**
041 * Cryptographic curve. This class is immutable.
042 *
043 * <p>Includes constants for the following standard cryptographic
044 * curves:
045 *
046 * <ul>
047 * <li>{@link #P_256}
048 * <li>{@link #P_384}
049 * <li>{@link #P_521}
050 * </ul>
051 *
052 * <p>See "Digital Signature Standard (DSS)", FIPS PUB 186-3, June 2009,
053 * National Institute of Standards and Technology (NIST).
054 */
055 @Immutable
056 public static class Curve {
057
058
059 /**
060 * P-256 curve.
061 */
062 public static final Curve P_256 = new Curve("P-256");
063
064
065 /**
066 * P-384 curve.
067 */
068 public static final Curve P_384 = new Curve("P-384");
069
070
071 /**
072 * P-521 curve.
073 */
074 public static final Curve P_521 = new Curve("P-521");
075
076
077 /**
078 * The curve name.
079 */
080 private final String name;
081
082
083 /**
084 * Creates a new cryptographic curve with the specified name.
085 *
086 * @param name The name of the cryptographic curve. Must not be
087 * {@code null}.
088 */
089 public Curve(final String name) {
090
091 if (name == null)
092 throw new IllegalArgumentException("The cryptographic curve name must not be null");
093
094 this.name = name;
095 }
096
097
098 /**
099 * Gets the name of this cryptographic curve.
100 *
101 * @return The name.
102 */
103 public String getName() {
104
105 return name;
106 }
107
108
109 /**
110 * @see #getName
111 */
112 @Override
113 public String toString() {
114
115 return getName();
116 }
117
118
119 /**
120 * Overrides {@code Object.equals()}.
121 *
122 * @param object The object to compare to.
123 *
124 * @return {@code true} if the objects have the same value,
125 * otherwise {@code false}.
126 */
127 @Override
128 public boolean equals(final Object object) {
129
130 return object != null &&
131 object instanceof Curve &&
132 this.toString().equals(object.toString());
133 }
134
135
136 /**
137 * Parses a cryptographic curve from the specified string.
138 *
139 * @param s The string to parse. Must not be {@code null}.
140 *
141 * @return The cryptographic curve.
142 *
143 * @throws ParseException If the string couldn't be parsed.
144 */
145 public static Curve parse(final String s)
146 throws ParseException {
147
148 if (s == null)
149 throw new IllegalArgumentException("The cryptographic curve sting must not be null");
150
151 if (s == P_256.getName())
152 return P_256;
153
154 else if (s == P_384.getName())
155 return P_384;
156
157 else if (s == P_521.getName())
158 return P_521;
159
160 else
161 return new Curve(s);
162 }
163 }
164
165
166 /**
167 * The curve name.
168 */
169 private final Curve crv;
170
171
172 /**
173 * The 'x' EC coordinate.
174 */
175 private final Base64URL x;
176
177
178 /**
179 * The 'y' EC coordinate.
180 */
181 private final Base64URL y;
182
183
184 /**
185 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the
186 * specified parameters.
187 *
188 * @param crv The cryptographic curve. Must not be {@code null}.
189 * @param x The 'x' coordinate for the elliptic curve point. It is
190 * represented as the Base64URL encoding of the coordinate's
191 * big endian representation. Must not be {@code null}.
192 * @param y The 'y' coordinate for the elliptic curve point. It is
193 * represented as the Base64URL encoding of the coordinate's
194 * big endian representation. Must not be {@code null}.
195 * @param use The key use, {@code null} if not specified.
196 * @param alg The intended JOSE algorithm for the key, {@code null} if
197 * not specified.
198 * @param kid The key ID, {@code null} if not specified.
199 */
200 public ECKey(final Curve crv, final Base64URL x, final Base64URL y,
201 final Use use, final Algorithm alg, final String kid) {
202
203 super(KeyType.EC, use, alg, kid);
204
205 if (crv == null)
206 throw new IllegalArgumentException("The curve must not be null");
207
208 this.crv = crv;
209
210 if (x == null)
211 throw new IllegalArgumentException("The x coordinate must not be null");
212
213 this.x = x;
214
215 if (y == null)
216 throw new IllegalArgumentException("The y coordinate must not be null");
217
218 this.y = y;
219 }
220
221
222 /**
223 * Gets the cryptographic curve.
224 *
225 * @return The cryptographic curve.
226 */
227 public Curve getCurve() {
228
229 return crv;
230 }
231
232
233 /**
234 * Gets the 'x' coordinate for the elliptic curve point. It is
235 * represented as the Base64URL encoding of the coordinate's big endian
236 * representation.
237 *
238 * @return The 'x' coordinate.
239 */
240 public Base64URL getX() {
241
242 return x;
243 }
244
245
246 /**
247 * Gets the 'y' coordinate for the elliptic curve point. It is
248 * represented as the Base64URL encoding of the coordinate's big endian
249 * representation.
250 *
251 * @return The 'y' coordinate.
252 */
253 public Base64URL getY() {
254
255 return y;
256 }
257
258
259 @Override
260 public JSONObject toJSONObject() {
261
262 JSONObject o = super.toJSONObject();
263
264 // Append EC specific attributes
265 o.put("crv", crv.toString());
266 o.put("x", x.toString());
267 o.put("y", y.toString());
268
269 return o;
270 }
271
272
273 /**
274 * Parses an Elliptic Curve JWK from the specified JSON object
275 * representation.
276 *
277 * @param jsonObject The JSON object to parse. Must not be
278 * {@code null}.
279 *
280 * @return The Elliptic Curve JWK.
281 *
282 * @throws ParseException If the JSON object couldn't be parsed to a
283 * valid Elliptic Curve JWK.
284 */
285 public static ECKey parse(final JSONObject jsonObject)
286 throws ParseException {
287
288 // Parse the mandatory parameters first
289 KeyType kty = KeyType.parse(JSONObjectUtils.getString(jsonObject, "kty"));
290 Curve crv = Curve.parse(JSONObjectUtils.getString(jsonObject, "crv"));
291 Base64URL x = new Base64URL(JSONObjectUtils.getString(jsonObject, "x"));
292 Base64URL y = new Base64URL(JSONObjectUtils.getString(jsonObject, "y"));
293
294 // Get optional key use
295 Use use = JWK.parseKeyUse(jsonObject);
296
297 // Get optional intended algorithm
298 Algorithm alg = JWK.parseAlgorithm(jsonObject);
299
300 // Get optional key ID
301 String id = JWK.parseKeyID(jsonObject);
302
303 // Check key type
304 if (kty != KeyType.EC)
305 throw new ParseException("The key type \"kty\" must be EC", 0);
306
307 return new ECKey(crv, x, y, use, alg, id);
308 }
309 }