package com.nimbusds.jose;
import java.text.ParseException;
import net.minidev.json.JSONAware;
import net.minidev.json.JSONObject;
import com.nimbusds.jose.util.JSONObjectUtils;
/**
* The base abstract class for public JSON Web Keys (JWKs). It serialises to a
* JSON object.
*
* <p>The following JSON object members are common to all JWK types:
*
* <ul>
* <li>{@link #getAlgorithmFamily alg} (required)
* <li>{@link #getKeyUse use} (optional)
* <li>{@link #getKeyID kid} (optional)
* </ul>
*
* <p>Example JWK (of the Elliptic Curve type):
*
* <pre>
* {
* "alg" : "EC",
* "crv" : "P-256",
* "x" : "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
* "y" : "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
* "use" : "enc",
* "kid" : "1"
* }
* </pre>
*
* @author Vladimir Dzhuvinov
* @version $version$ (2012-09-22)
*/
public abstract class JWK implements JSONAware {
/**
* The algorithm family, required.
*/
private final AlgorithmFamily alg;
/**
* The use, optional.
*/
private final Use use;
/**
* The key ID, optional.
*/
private final String kid;
/**
* Creates a new JSON Web Key (JWK) with the specified parameters.
*
* @param alg The JOSE algorithm family. Must not be {@code null}.
* @param use The key use, {@code null} if not specified or if the key
* is intended for signing as well as encryption.
* @param kid The key ID, {@code null} if not specified.
*/
public JWK(final AlgorithmFamily alg, final Use use, final String kid) {
if (alg == null)
throw new IllegalArgumentException("The algorithm family \"alg\" must not be null");
this.alg = alg;
this.use = use;
this.kid = kid;
}
/**
* Gets the JOSE algorithm family ({@code alg}) of this JWK.
*
* @return The JOSE algorithm family.
*/
public AlgorithmFamily getAlgorithmFamily() {
return alg;
}
/**
* Gets the use ({@code use}) of this JWK.
*
* @return The key use, {@code null} if not specified or if the key is
* intended for signing as well as encryption.
*/
public Use getKeyUse() {
return use;
}
/**
* Gets the ID ({@code kid}) of this JWK. The key ID can be used to
* match a specific key. This can be used, for instance, to choose a key
* within a {@link JWKSet} during key rollover. The key ID may also
* correspond to a JWS/JWE {@code kid} header parameter value.
*
* @return The key ID, {@code null} if not specified.
*/
public String getKeyID() {
return kid;
}
/**
* Returns a JSON object representation of this JWK. This method is
* intended to be called from extending classes.
*
* <p>Example:
*
* <pre>
* {
* "alg" : "RSA",
* "use" : "sig",
* "kid" : "fd28e025-8d24-48bc-a51a-e2ffc8bc274b"
* }
* </pre>
*
* @return The JSON object representation.
*/
public JSONObject toJSONObject() {
JSONObject o = new JSONObject();
o.put("alg", alg.toString());
if (use != null) {
if (use == Use.SIGNATURE)
o.put("use", "sig");
if (use == Use.ENCRYPTION)
o.put("use", "enc");
}
if (kid != null)
o.put("kid", kid);
return o;
}
/**
* Returns the JSON object string representation of this JWK.
*
* @return The JSON object string representation.
*/
@Override
public String toJSONString() {
return toJSONObject().toString();
}
/**
* @see #toJSONString
*/
@Override
public String toString() {
return toJSONObject().toString();
}
/**
* Parses a JWK from the specified JSON object string representation.
* The JWK must be an {@link ECKey} or an {@link RSAKey}.
*
* @param s The JSON object string to parse. Must not be {@code null}.
*
* @return The JWK.
*
* @throws ParseException If the string couldn't be parsed to valid and
* supported JWK.
*/
public static JWK parse(final String s)
throws ParseException {
return parse(JSONObjectUtils.parseJSONObject(s));
}
/**
* Parses a JWK from the specified JSON object representation. The JWK
* must be an {@link ECKey} or an {@link RSAKey}.
*
* @param jsonObject The JSON object to parse. Must not be {@code null}.
*
* @return The JWK.
*
* @throws ParseException If the JSON object couldn't be parsed to a
* valid and supported JWK.
*/
public static JWK parse(final JSONObject jsonObject)
throws ParseException {
AlgorithmFamily alg = AlgorithmFamily.parse(JSONObjectUtils.getString(jsonObject, "alg"));
if (alg == AlgorithmFamily.EC)
return ECKey.parse(jsonObject);
else if (alg == AlgorithmFamily.RSA)
return RSAKey.parse(jsonObject);
else
throw new ParseException("Unsupported algorithm family \"alg\" parameter: " + alg, 0);
}
/**
* Parses a key use ({@code use}) parameter from the specified JSON
* object representation of a JWK.
*
* @param jsonObject The JSON object to parse. Must not be {@code null}.
*
* @return The key use, {@code null} if not specified.
*
* @throws ParseException If the key use parameter couldn't be parsed.
*/
protected static Use parseKeyUse(final JSONObject jsonObject)
throws ParseException {
if (jsonObject.get("use") == null)
return null;
String useStr = JSONObjectUtils.getString(jsonObject, "use");
if (useStr.equals("sig"))
return Use.SIGNATURE;
else if (useStr.equals("enc"))
return Use.ENCRYPTION;
else
throw new ParseException("Invalid or unsupported key use \"use\" parameter, must be \"sig\" or \"enc\"", 0);
}
/**
* Parses a key ID ({@code kid}) parameter from the specified JSON
* object representation of a JWK.
*
* @param jsonObject The JSON object to parse. Must not be {@code null}.
*
* @return The key ID, {@code null} if not specified.
*
* @throws ParseException if the key ID parameter couldn't be parsed.
*/
protected static String parseKeyID(final JSONObject jsonObject)
throws ParseException {
if (jsonObject.get("kid") == null)
return null;
return JSONObjectUtils.getString(jsonObject, "kid");
}
}