001package com.nimbusds.jose.jwk; 002 003 004import java.net.URL; 005import java.util.List; 006import java.text.ParseException; 007 008import net.jcip.annotations.Immutable; 009 010import net.minidev.json.JSONObject; 011 012import com.nimbusds.jose.Algorithm; 013import com.nimbusds.jose.util.Base64; 014import com.nimbusds.jose.util.Base64URL; 015import com.nimbusds.jose.util.JSONObjectUtils; 016import com.nimbusds.jose.util.X509CertChainUtils; 017 018 019/** 020 * {@link KeyType#OCT Octet sequence} JSON Web Key (JWK), used to represent 021 * symmetric keys. This class is immutable. 022 * 023 * <p>Example JSON object representation of an octet sequence JWK: 024 * 025 * <pre> 026 * { 027 * "kty" : "oct", 028 * "alg" : "A128KW", 029 * "k" : "GawgguFyGrWKav7AX4VKUg" 030 * } 031 * </pre> 032 * 033 * @author Justin Richer 034 * @author Vladimir Dzhuvinov 035 * @version $version$ (2013-12-22) 036 */ 037@Immutable 038public class OctetSequenceKey extends JWK { 039 040 041 /** 042 * The symmetric key value. 043 */ 044 private final Base64URL k; 045 046 /** 047 * Builder for constructing octet sequence JWKs. 048 * 049 * <p>Example use: 050 * 051 * <pre> 052 * OctetSequenceKey key = new OctetSequenceKey.Builder(k). 053 * algorithm(JWSAlgorithm.HS512). 054 * keyID("123"). 055 * build(); 056 * </pre> 057 */ 058 public static class Builder { 059 060 061 /** 062 * The symmetric key value. 063 */ 064 private final Base64URL k; 065 066 067 /** 068 * The key use, optional. 069 */ 070 private Use use; 071 072 073 /** 074 * The intended JOSE algorithm for the key, optional. 075 */ 076 private Algorithm alg; 077 078 079 /** 080 * The key ID, optional. 081 */ 082 private String kid; 083 084 085 /** 086 * X.509 certificate URL, optional. 087 */ 088 private URL x5u; 089 090 091 /** 092 * X.509 certificate thumbprint, optional. 093 */ 094 private Base64URL x5t; 095 096 097 /** 098 * The X.509 certificate chain, optional. 099 */ 100 private List<Base64> x5c; 101 102 103 /** 104 * Creates a new octet sequence JWK builder. 105 * 106 * @param k The key value. It is represented as the Base64URL 107 * encoding of value's big endian representation. Must 108 * not be {@code null}. 109 */ 110 public Builder(final Base64URL k) { 111 112 if (k == null) { 113 throw new IllegalArgumentException("The key value must not be null"); 114 } 115 116 this.k = k; 117 } 118 119 120 /** 121 * Sets the use ({@code use}) of the JWK. 122 * 123 * @param use The key use, {@code null} if not specified or if 124 * the key is intended for signing as well as 125 * encryption. 126 * 127 * @return This builder. 128 */ 129 public Builder keyUse(final Use use) { 130 131 this.use = use; 132 return this; 133 } 134 135 136 /** 137 * Sets the intended JOSE algorithm ({@code alg}) for the JWK. 138 * 139 * @param alg The intended JOSE algorithm, {@code null} if not 140 * specified. 141 * 142 * @return This builder. 143 */ 144 public Builder algorithm(final Algorithm alg) { 145 146 this.alg = alg; 147 return this; 148 } 149 150 /** 151 * Sets the ID ({@code kid}) of the JWK. The key ID can be used 152 * to match a specific key. This can be used, for instance, to 153 * choose a key within a {@link JWKSet} during key rollover. 154 * The key ID may also correspond to a JWS/JWE {@code kid} 155 * header parameter value. 156 * 157 * @param kid The key ID, {@code null} if not specified. 158 * 159 * @return This builder. 160 */ 161 public Builder keyID(final String kid) { 162 163 this.kid = kid; 164 return this; 165 } 166 167 168 /** 169 * Sets the X.509 certificate URL ({@code x5u}) of the JWK. 170 * 171 * @param x5u The X.509 certificate URL, {@code null} if not 172 * specified. 173 * 174 * @return This builder. 175 */ 176 public Builder x509CertURL(final URL x5u) { 177 178 this.x5u = x5u; 179 return this; 180 } 181 182 183 /** 184 * Sets the X.509 certificate thumbprint ({@code x5t}) of the 185 * JWK. 186 * 187 * @param x5t The X.509 certificate thumbprint, {@code null} if 188 * not specified. 189 * 190 * @return This builder. 191 */ 192 public Builder x509CertThumbprint(final Base64URL x5t) { 193 194 this.x5t = x5t; 195 return this; 196 } 197 198 /** 199 * Sets the X.509 certificate chain ({@code x5c}) of the JWK. 200 * 201 * @param x5c The X.509 certificate chain as a unmodifiable 202 * list, {@code null} if not specified. 203 * 204 * @return This builder. 205 */ 206 public Builder x509CertChain(final List<Base64> x5c) { 207 208 this.x5c = x5c; 209 return this; 210 } 211 212 /** 213 * Builds a new octet sequence JWK. 214 * 215 * @return The octet sequence JWK. 216 */ 217 public OctetSequenceKey build() { 218 219 return new OctetSequenceKey(k, use, alg, kid, x5u, x5t, x5c); 220 } 221 } 222 223 224 /** 225 * Creates a new octet sequence JSON Web Key (JWK) with the specified 226 * parameters. 227 * 228 * @param k The key value. It is represented as the Base64URL 229 * encoding of value's big endian representation. Must not 230 * be {@code null}. 231 * @param use The key use. {@code null} if not specified. 232 * @param alg The intended JOSE algorithm for the key, {@code null} if 233 * not specified. 234 * @param kid The key ID. {@code null} if not specified. 235 * @param x5u The X.509 certificate URL, {@code null} if not specified. 236 * @param x5t The X.509 certificate thumbprint, {@code null} if not 237 * specified. 238 * @param x5c The X.509 certificate chain, {@code null} if not 239 * specified. 240 */ 241 public OctetSequenceKey(final Base64URL k, final Use use, final Algorithm alg, final String kid, 242 final URL x5u, final Base64URL x5t, final List<Base64> x5c) { 243 244 super(KeyType.OCT, use, alg, kid, x5u, x5t, x5c); 245 246 if (k == null) { 247 throw new IllegalArgumentException("The key value must not be null"); 248 } 249 250 this.k = k; 251 } 252 253 254 /** 255 * Returns the value of this octet sequence key. 256 * 257 * @return The key value. It is represented as the Base64URL encoding 258 * of the coordinate's big endian representation. 259 */ 260 public Base64URL getKeyValue() { 261 262 return k; 263 } 264 265 266 /** 267 * Returns a copy of this octet sequence key value as a byte array. 268 * 269 * @return The key value as a byte array. 270 */ 271 public byte[] toByteArray() { 272 273 return getKeyValue().decode(); 274 } 275 276 277 /** 278 * Octet sequence (symmetric) keys are never considered public, this 279 * method always returns {@code true}. 280 * 281 * @return {@code true} 282 */ 283 @Override 284 public boolean isPrivate() { 285 286 return true; 287 } 288 289 290 /** 291 * Octet sequence (symmetric) keys are never considered public, this 292 * method always returns {@code null}. 293 * 294 * @return {@code null} 295 */ 296 @Override 297 public OctetSequenceKey toPublicJWK() { 298 299 return null; 300 } 301 302 303 @Override 304 public JSONObject toJSONObject() { 305 306 JSONObject o = super.toJSONObject(); 307 308 // Append key value 309 o.put("k", k.toString()); 310 311 return o; 312 } 313 314 315 /** 316 * Parses an octet sequence JWK from the specified JSON object string 317 * representation. 318 * 319 * @param s The JSON object string to parse. Must not be {@code null}. 320 * 321 * @return The octet sequence JWK. 322 * 323 * @throws ParseException If the string couldn't be parsed to an octet 324 * sequence JWK. 325 */ 326 public static OctetSequenceKey parse(final String s) 327 throws ParseException { 328 329 return parse(JSONObjectUtils.parseJSONObject(s)); 330 } 331 332 333 /** 334 * Parses an octet sequence JWK from the specified JSON object 335 * representation. 336 * 337 * @param jsonObject The JSON object to parse. Must not be 338 * @code null}. 339 * 340 * @return The octet sequence JWK. 341 * 342 * @throws ParseException If the JSON object couldn't be parsed to an 343 * octet sequence JWK. 344 */ 345 public static OctetSequenceKey parse(final JSONObject jsonObject) 346 throws ParseException { 347 348 // Parse the mandatory parameters first 349 Base64URL k = new Base64URL(JSONObjectUtils.getString(jsonObject, "k")); 350 351 // Check key type 352 KeyType kty = KeyType.parse(JSONObjectUtils.getString(jsonObject, "kty")); 353 354 if (kty != KeyType.OCT) { 355 356 throw new ParseException("The key type \"kty\" must be oct", 0); 357 } 358 359 // Get optional key use 360 Use use = null; 361 362 if (jsonObject.containsKey("use")) { 363 use = Use.parse(JSONObjectUtils.getString(jsonObject, "use")); 364 } 365 366 // Get optional intended algorithm 367 Algorithm alg = null; 368 369 if (jsonObject.containsKey("alg")) { 370 alg = new Algorithm(JSONObjectUtils.getString(jsonObject, "alg")); 371 } 372 373 // Get optional key ID 374 String kid = null; 375 376 if (jsonObject.containsKey("kid")) { 377 kid = JSONObjectUtils.getString(jsonObject, "kid"); 378 } 379 380 // Get optional X.509 cert URL 381 URL x5u = null; 382 383 if (jsonObject.containsKey("x5u")) { 384 x5u = JSONObjectUtils.getURL(jsonObject, "x5u"); 385 } 386 387 // Get optional X.509 cert thumbprint 388 Base64URL x5t = null; 389 390 if (jsonObject.containsKey("x5t")) { 391 x5t = new Base64URL(JSONObjectUtils.getString(jsonObject, "x5t")); 392 } 393 394 // Get optional X.509 cert chain 395 List<Base64> x5c = null; 396 397 if (jsonObject.containsKey("x5c")) { 398 x5c = X509CertChainUtils.parseX509CertChain(JSONObjectUtils.getJSONArray(jsonObject, "x5c")); 399 } 400 401 return new OctetSequenceKey(k, use, alg, kid, x5u, x5t, x5c); 402 } 403}