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}