001 package com.nimbusds.jose;
002
003
004 import java.net.URL;
005
006 import java.text.ParseException;
007
008 import java.util.Collections;
009 import java.util.HashSet;
010 import java.util.Set;
011
012 import net.minidev.json.JSONArray;
013 import net.minidev.json.JSONObject;
014
015 import com.nimbusds.jose.util.Base64URL;
016 import com.nimbusds.jose.util.JSONObjectUtils;
017
018
019 /**
020 * JSON Web Encryption (JWE) header.
021 *
022 * <p>Supports all {@link #getReservedParameterNames reserved header parameters}
023 * of the JWE specification:
024 *
025 * <ul>
026 * <li>alg
027 * <li>enc
028 * <li>epk
029 * <li>zip
030 * <li>jku
031 * <li>jwk
032 * <li>x5u
033 * <li>x5t
034 * <li>x5c
035 * <li>kid
036 * <li>typ
037 * <li>cty
038 * <li>apu
039 * <li>apv
040 * <li>epu
041 * <li>epv
042 * </ul>
043 *
044 * <p>The header may also carry {@link #setCustomParameters custom parameters};
045 * these will be serialised and parsed along the reserved ones.
046 *
047 * <p>Example header:
048 *
049 * <pre>
050 * {
051 * "alg" : "RSA1_5",
052 * "enc" : "A128CBC+HS256"
053 * }
054 * </pre>
055 *
056 * @author Vladimir Dzhuvinov
057 * @version $version$ (2013-01-08)
058 */
059 public class JWEHeader extends CommonSEHeader implements ReadOnlyJWEHeader {
060
061
062 /**
063 * The reserved parameter names.
064 */
065 private static final Set<String> RESERVED_PARAMETER_NAMES;
066
067
068 /**
069 * Initialises the reserved parameter name set.
070 */
071 static {
072 Set<String> p = new HashSet<String>();
073
074 p.add("alg");
075 p.add("enc");
076 p.add("epk");
077 p.add("zip");
078 p.add("jku");
079 p.add("jwk");
080 p.add("x5u");
081 p.add("x5t");
082 p.add("x5c");
083 p.add("kid");
084 p.add("typ");
085 p.add("cty");
086 p.add("apu");
087 p.add("apv");
088 p.add("epu");
089 p.add("epv");
090
091 RESERVED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
092 }
093
094
095 /**
096 * The encryption method ({@code enc}) parameter.
097 */
098 private EncryptionMethod enc;
099
100
101 /**
102 * The ephemeral public key ({@code epk}) parameter.
103 */
104 private ECKey epk;
105
106
107 /**
108 * The compression algorithm ({@code zip}) parameter.
109 */
110 private CompressionAlgorithm zip;
111
112
113 /**
114 * The agreement PartyUInfo ({@code apu}) parameter.
115 */
116 private Base64URL apu;
117
118
119 /**
120 * The agreement PartyVInfo ({@code apv}) parameter.
121 */
122 private Base64URL apv;
123
124
125 /**
126 * The encryption PartyUInfo ({@code epu}) parameter.
127 */
128 private Base64URL epu;
129
130
131 /**
132 * The encryption PartyUInfo ({@code epv}) parameter.
133 */
134 private Base64URL epv;
135
136
137 /**
138 * Creates a new JSON Web Encryption (JWE) header.
139 *
140 * @param alg The JWE algorithm parameter. Must not be {@code null}.
141 * @param enc The encryption method parameter. Must not be {@code null}.
142 */
143 public JWEHeader(final JWEAlgorithm alg, final EncryptionMethod enc) {
144
145 super(alg);
146
147 if (enc == null)
148 throw new IllegalArgumentException("The encryption method \"enc\" parameter must not be null");
149
150 this.enc = enc;
151 }
152
153
154 /**
155 * Gets the reserved parameter names for JWE headers.
156 *
157 * @return The reserved parameter names, as an unmodifiable set.
158 */
159 public static Set<String> getReservedParameterNames() {
160
161 return RESERVED_PARAMETER_NAMES;
162 }
163
164
165 @Override
166 public JWEAlgorithm getAlgorithm() {
167
168 return (JWEAlgorithm)alg;
169 }
170
171
172 @Override
173 public EncryptionMethod getEncryptionMethod() {
174
175 return enc;
176 }
177
178
179 @Override
180 public ECKey getEphemeralPublicKey() {
181
182 return epk;
183 }
184
185
186 /**
187 * Sets the Ephemeral Public Key ({@code epk}) parameter.
188 *
189 * @param epk The Ephemeral Public Key parameter, {@code null} if not
190 * specified.
191 */
192 public void setEphemeralPublicKey(final ECKey epk) {
193
194 this.epk = epk;
195 }
196
197
198 @Override
199 public CompressionAlgorithm getCompressionAlgorithm() {
200
201 return zip;
202 }
203
204
205 /**
206 * Sets the compression algorithm ({@code zip}) parameter.
207 *
208 * @param zip The compression algorithm parameter, {@code null} if not
209 * specified.
210 */
211 public void setCompressionAlgorithm(final CompressionAlgorithm zip) {
212
213 this.zip = zip;
214 }
215
216
217 @Override
218 public Base64URL getAgreementPartyUInfo() {
219
220 return apu;
221 }
222
223
224 /**
225 * Sets the agreement PartyUInfo ({@code apu}) parameter.
226 *
227 * @param apu The agreement PartyUInfo parameter, {@code null} if not
228 * specified.
229 */
230 public void setAgreementPartyUInfo(final Base64URL apu) {
231
232 this.apu = apu;
233 }
234
235
236 @Override
237 public Base64URL getAgreementPartyVInfo() {
238
239 return apv;
240 }
241
242
243 /**
244 * Sets the agreement PartyVInfo ({@code apv}) parameter.
245 *
246 * @param apv The agreement PartyVInfo parameter, {@code null} if not
247 * specified.
248 */
249 public void setAgreementPartyVInfo(final Base64URL apv) {
250
251 this.apv = apv;
252 }
253
254
255 @Override
256 public Base64URL getEncryptionPartyUInfo() {
257
258 return epu;
259 }
260
261
262 /**
263 * Sets the encryption PartyUInfo ({@code epu}) parameter.
264 *
265 * @param epu The encryption PartyUInfo parameter, {@code null} if not
266 * specified.
267 */
268 public void setEncryptionPartyUInfo(final Base64URL epu) {
269
270 this.epu = epu;
271 }
272
273
274 @Override
275 public Base64URL getEncryptionPartyVInfo() {
276
277 return epv;
278 }
279
280
281 /**
282 * Sets the encryption PartyVInfo ({@code epv}) parameter.
283 *
284 * @param epv The encryption PartyVInfo parameter, {@code null} if not
285 * specified.
286 */
287 public void setEncryptionPartyVInfo(final Base64URL epv) {
288
289 this.epv = epv;
290 }
291
292
293 /**
294 * @throws IllegalArgumentException If the specified parameter name
295 * matches a reserved parameter name.
296 */
297 @Override
298 public void setCustomParameter(final String name, final Object value) {
299
300 if (getReservedParameterNames().contains(name))
301 throw new IllegalArgumentException("The parameter name \"" + name + "\" matches a reserved name");
302
303 super.setCustomParameter(name, value);
304 }
305
306
307 @Override
308 public Set<String> getIncludedParameters() {
309
310 Set<String> includedParameters =
311 new HashSet<String>(getCustomParameters().keySet());
312
313 includedParameters.add("alg");
314 includedParameters.add("enc");
315
316 if (getEphemeralPublicKey() != null)
317 includedParameters.add("epk");
318
319 if (getCompressionAlgorithm() != null)
320 includedParameters.add("zip");
321
322 if (getType() != null)
323 includedParameters.add("typ");
324
325 if (getContentType() != null)
326 includedParameters.add("cty");
327
328 if (getJWKURL() != null)
329 includedParameters.add("jku");
330
331 if (getJWK() != null)
332 includedParameters.add("jwk");
333
334 if (getX509CertURL() != null)
335 includedParameters.add("x5u");
336
337 if (getX509CertThumbprint() != null)
338 includedParameters.add("x5t");
339
340 if (getX509CertChain() != null)
341 includedParameters.add("x5c");
342
343 if (getKeyID() != null)
344 includedParameters.add("kid");
345
346 if (getAgreementPartyUInfo() != null)
347 includedParameters.add("apu");
348
349 if (getAgreementPartyVInfo() != null)
350 includedParameters.add("apv");
351
352 if (getEncryptionPartyUInfo() != null)
353 includedParameters.add("epu");
354
355 if (getEncryptionPartyVInfo() != null)
356 includedParameters.add("epv");
357
358 return includedParameters;
359 }
360
361
362 @Override
363 public JSONObject toJSONObject() {
364
365 JSONObject o = super.toJSONObject();
366
367 if (enc != null)
368 o.put("enc", enc.toString());
369
370 if (epk != null)
371 o.put("epk", epk.toJSONObject());
372
373 if (zip != null)
374 o.put("zip", zip.toString());
375
376 if (apu != null)
377 o.put("apu", apu.toString());
378
379 if (apv != null)
380 o.put("apv", apv.toString());
381
382 if (epu != null)
383 o.put("epu", epu.toString());
384
385 if (epv != null)
386 o.put("epv", epv.toString());
387
388 return o;
389 }
390
391
392 /**
393 * Parses an encryption method ({@code enc}) parameter from the
394 * specified JWE header JSON object.
395 *
396 * @param json The JSON object to parse. Must not be {@code null}.
397 *
398 * @return The encryption method.
399 *
400 * @throws ParseException If the {@code enc} parameter couldn't be
401 * parsed.
402 */
403 private static EncryptionMethod parseEncryptionMethod(final JSONObject json)
404 throws ParseException {
405
406 return EncryptionMethod.parse(JSONObjectUtils.getString(json, "enc"));
407 }
408
409
410 /**
411 * Parses a JWE header from the specified JSON object.
412 *
413 * @param json The JSON object to parse. Must not be {@code null}.
414 *
415 * @return The JWE header.
416 *
417 * @throws ParseException If the specified JSON object doesn't
418 * represent a valid JWE header.
419 */
420 public static JWEHeader parse(final JSONObject json)
421 throws ParseException {
422
423 // Get the "alg" parameter
424 Algorithm alg = Header.parseAlgorithm(json);
425
426 if (! (alg instanceof JWEAlgorithm))
427 throw new ParseException("The algorithm \"alg\" header parameter must be for encryption", 0);
428
429 // Get the "enc" parameter
430 EncryptionMethod enc = parseEncryptionMethod(json);
431
432 // Create a minimal header
433 JWEHeader h = new JWEHeader((JWEAlgorithm)alg, enc);
434
435 // Parse optional + custom parameters
436 for(final String name: json.keySet()) {
437
438 if (name.equals("alg"))
439 continue; // skip
440
441 else if (name.equals("enc"))
442 continue; // skip
443
444 else if (name.equals("epk"))
445 h.setEphemeralPublicKey(ECKey.parse(JSONObjectUtils.getJSONObject(json, name)));
446
447 else if (name.equals("zip"))
448 h.setCompressionAlgorithm(new CompressionAlgorithm(JSONObjectUtils.getString(json, name)));
449
450 else if (name.equals("typ"))
451 h.setType(new JOSEObjectType(JSONObjectUtils.getString(json, name)));
452
453 else if (name.equals("cty"))
454 h.setContentType(JSONObjectUtils.getString(json, name));
455
456 else if (name.equals("jku"))
457 h.setJWKURL(JSONObjectUtils.getURL(json, name));
458
459 else if (name.equals("jwk"))
460 h.setJWK(JWK.parse(JSONObjectUtils.getJSONObject(json, name)));
461
462 else if (name.equals("x5u"))
463 h.setX509CertURL(JSONObjectUtils.getURL(json, name));
464
465 else if (name.equals("x5t"))
466 h.setX509CertThumbprint(new Base64URL(JSONObjectUtils.getString(json, name)));
467
468 else if (name.equals("x5c"))
469 h.setX509CertChain(CommonSEHeader.parseX509CertChain(JSONObjectUtils.getJSONArray(json, name)));
470
471 else if (name.equals("kid"))
472 h.setKeyID(JSONObjectUtils.getString(json, name));
473
474 else if (name.equals("apu"))
475 h.setAgreementPartyUInfo(new Base64URL(JSONObjectUtils.getString(json, name)));
476
477 else if (name.equals("apv"))
478 h.setAgreementPartyVInfo(new Base64URL(JSONObjectUtils.getString(json, name)));
479
480 else if (name.equals("epu"))
481 h.setEncryptionPartyUInfo(new Base64URL(JSONObjectUtils.getString(json, name)));
482
483 else if (name.equals("epv"))
484 h.setEncryptionPartyVInfo(new Base64URL(JSONObjectUtils.getString(json, name)));
485
486 else
487 h.setCustomParameter(name, json.get(name));
488
489 }
490
491 return h;
492 }
493
494
495 /**
496 * Parses a JWE header from the specified JSON string.
497 *
498 * @param s The JSON string to parse. Must not be {@code null}.
499 *
500 * @return The JWE header.
501 *
502 * @throws ParseException If the specified JSON object string doesn't
503 * represent a valid JWE header.
504 */
505 public static JWEHeader parse(final String s)
506 throws ParseException {
507
508 JSONObject jsonObject = JSONObjectUtils.parseJSONObject(s);
509
510 return parse(jsonObject);
511 }
512
513
514 /**
515 * Parses a JWE header from the specified Base64URL.
516 *
517 * @param base64URL The Base64URL to parse. Must not be {@code null}.
518 *
519 * @return The JWE header.
520 *
521 * @throws ParseException If the specified Base64URL doesn't represent a
522 * valid JWE header.
523 */
524 public static JWEHeader parse(final Base64URL base64URL)
525 throws ParseException {
526
527 return parse(base64URL.decodeToString());
528 }
529 }