001package com.nimbusds.jose.proc; 002 003 004import java.security.Key; 005import java.text.ParseException; 006import java.util.List; 007import java.util.ListIterator; 008 009import com.nimbusds.jose.*; 010import com.nimbusds.jose.crypto.factories.DefaultJWEDecrypterFactory; 011import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory; 012import net.jcip.annotations.ThreadSafe; 013 014 015/** 016 * Default processor of {@link com.nimbusds.jose.PlainObject unsecured} 017 * (plain), {@link com.nimbusds.jose.JWSObject JWS} and 018 * {@link com.nimbusds.jose.JWEObject JWE} objects. 019 * 020 * <p>Must be configured with the following: 021 * 022 * <ol> 023 * <li>To verify JWS objects: A {@link JWSKeySelector JWS key selector} to 024 * determine the key candidate(s) for the signature verification. The key 025 * selection procedure is application-specific and may involve key ID 026 * lookup, a certificate check and / or other information supplied in the 027 * message {@link SecurityContext context}.</li> 028 * 029 * <li>To decrypt JWE objects: A {@link JWEKeySelector JWE key selector} to 030 * determine the key candidate(s) for decryption. The key selection 031 * procedure is application-specific and may involve key ID lookup, a 032 * certificate check and / or other information supplied in the message 033 * {@link SecurityContext context}.</li> 034 * </ol> 035 * 036 * <p>An optional context parameter is available to facilitate passing of 037 * additional data between the caller and the underlying selector of key 038 * candidates (in both directions). 039 * 040 * <p>See sections 6 of RFC 7515 (JWS) and RFC 7516 (JWE) for guidelines on key 041 * selection. 042 * 043 * <p>This processor comes with the default {@link DefaultJWSVerifierFactory 044 * JWS verifier factory} and the default {@link DefaultJWEDecrypterFactory 045 * JWE decrypter factory}; they can construct verifiers / decrypters for all 046 * standard JOSE algorithms implemented by the library. 047 * 048 * <p>Note that for security reasons this processor is hardwired to reject 049 * unsecured (plain) JOSE objects. Override the {@link #process(PlainObject, 050 * SecurityContext)} method if you need to handle unsecured JOSE objects as 051 * well. 052 * 053 * <p>To process JSON Web Tokens (JWTs) use the 054 * {@link com.nimbusds.jwt.proc.DefaultJWTProcessor} class. 055 * 056 * @author Vladimir Dzhuvinov 057 * @version 2015-10-20 058 */ 059@ThreadSafe 060public class DefaultJOSEProcessor<C extends SecurityContext> implements ConfigurableJOSEProcessor<C>{ 061 062 // Cache exceptions 063 private static final BadJOSEException PLAIN_JOSE_REJECTED_EXCEPTION = 064 new BadJOSEException("Unsecured (plain) JOSE objects are rejected, extend class to handle"); 065 private static final BadJOSEException NO_JWS_KEY_SELECTOR_EXCEPTION = 066 new BadJOSEException("JWS object rejected: No JWS key selector is configured"); 067 private static final BadJOSEException NO_JWE_KEY_SELECTOR_EXCEPTION = 068 new BadJOSEException("JWE object rejected: No JWE key selector is configured"); 069 private static final JOSEException NO_JWS_VERIFIER_FACTORY_EXCEPTION = 070 new JOSEException("No JWS verifier is configured"); 071 private static final JOSEException NO_JWE_DECRYPTER_FACTORY_EXCEPTION = 072 new JOSEException("No JWE decrypter is configured"); 073 private static final BadJOSEException NO_JWS_KEY_CANDIDATES_EXCEPTION = 074 new BadJOSEException("JWS object rejected: No matching key(s) found"); 075 private static final BadJOSEException NO_JWE_KEY_CANDIDATES_EXCEPTION = 076 new BadJOSEException("JWE object rejected: No matching key(s) found"); 077 private static final BadJOSEException INVALID_SIGNATURE = 078 new BadJWSException("JWS object rejected: Invalid signature"); 079 private static final BadJOSEException NO_MATCHING_VERIFIERS_EXCEPTION = 080 new BadJOSEException("JWS object rejected: No matching verifier(s) found"); 081 private static final BadJOSEException NO_MATCHING_DECRYPTERS_EXCEPTION = 082 new BadJOSEException("JWE object rejected: No matching decrypter(s) found"); 083 084 085 /** 086 * The JWS key selector. 087 */ 088 private JWSKeySelector<C> jwsKeySelector; 089 090 091 /** 092 * The JWE key selector. 093 */ 094 private JWEKeySelector<C> jweKeySelector; 095 096 097 /** 098 * The JWS verifier factory. 099 */ 100 private JWSVerifierFactory jwsVerifierFactory = new DefaultJWSVerifierFactory(); 101 102 103 /** 104 * The JWE decrypter factory. 105 */ 106 private JWEDecrypterFactory jweDecrypterFactory = new DefaultJWEDecrypterFactory(); 107 108 109 @Override 110 public JWSKeySelector<C> getJWSKeySelector() { 111 112 return jwsKeySelector; 113 } 114 115 116 @Override 117 public void setJWSKeySelector(final JWSKeySelector<C> jwsKeySelector) { 118 119 this.jwsKeySelector = jwsKeySelector; 120 } 121 122 123 @Override 124 public JWEKeySelector<C> getJWEKeySelector() { 125 126 return jweKeySelector; 127 } 128 129 130 @Override 131 public void setJWEKeySelector(final JWEKeySelector<C> jweKeySelector) { 132 133 this.jweKeySelector = jweKeySelector; 134 } 135 136 137 @Override 138 public JWSVerifierFactory getJWSVerifierFactory() { 139 140 return jwsVerifierFactory; 141 } 142 143 144 @Override 145 public void setJWSVerifierFactory(final JWSVerifierFactory factory) { 146 147 jwsVerifierFactory = factory; 148 } 149 150 151 @Override 152 public JWEDecrypterFactory getJWEDecrypterFactory() { 153 154 return jweDecrypterFactory; 155 } 156 157 158 @Override 159 public void setJWEDecrypterFactory(final JWEDecrypterFactory factory) { 160 161 jweDecrypterFactory = factory; 162 } 163 164 165 @Override 166 public Payload process(final String compactJOSE, final C context) 167 throws ParseException, BadJOSEException, JOSEException { 168 169 return process(JOSEObject.parse(compactJOSE), context); 170 } 171 172 173 @Override 174 public Payload process(final JOSEObject joseObject, final C context) 175 throws BadJOSEException, JOSEException { 176 177 if (joseObject instanceof JWSObject) { 178 return process((JWSObject)joseObject, context); 179 } 180 181 if (joseObject instanceof JWEObject) { 182 return process((JWEObject)joseObject, context); 183 } 184 185 if (joseObject instanceof PlainObject) { 186 return process((PlainObject)joseObject, context); 187 } 188 189 // Should never happen 190 throw new JOSEException("Unexpected JOSE object type: " + joseObject.getClass()); 191 } 192 193 194 @Override 195 public Payload process(final PlainObject plainObject, C context) 196 throws BadJOSEException { 197 198 throw PLAIN_JOSE_REJECTED_EXCEPTION; 199 } 200 201 202 @Override 203 public Payload process(final JWSObject jwsObject, C context) 204 throws BadJOSEException, JOSEException { 205 206 if (getJWSKeySelector() == null) { 207 // JWS key selector may have been deliberately omitted 208 throw NO_JWS_KEY_SELECTOR_EXCEPTION; 209 } 210 211 if (getJWSVerifierFactory() == null) { 212 throw NO_JWS_VERIFIER_FACTORY_EXCEPTION; 213 } 214 215 List<? extends Key> keyCandidates = getJWSKeySelector().selectJWSKeys(jwsObject.getHeader(), context); 216 217 if (keyCandidates == null || keyCandidates.isEmpty()) { 218 throw NO_JWS_KEY_CANDIDATES_EXCEPTION; 219 } 220 221 ListIterator<? extends Key> it = keyCandidates.listIterator(); 222 223 while (it.hasNext()) { 224 225 JWSVerifier verifier = getJWSVerifierFactory().createJWSVerifier(jwsObject.getHeader(), it.next()); 226 227 if (verifier == null) { 228 continue; 229 } 230 231 final boolean validSignature = jwsObject.verify(verifier); 232 233 if (validSignature) { 234 return jwsObject.getPayload(); 235 } 236 237 if (! it.hasNext()) { 238 // No more keys to try out 239 throw INVALID_SIGNATURE; 240 } 241 } 242 243 throw NO_MATCHING_VERIFIERS_EXCEPTION; 244 } 245 246 247 @Override 248 public Payload process(final JWEObject jweObject, C context) 249 throws BadJOSEException, JOSEException { 250 251 if (getJWEKeySelector() == null) { 252 // JWE key selector may have been deliberately omitted 253 throw NO_JWE_KEY_SELECTOR_EXCEPTION; 254 } 255 256 if (getJWEDecrypterFactory() == null) { 257 throw NO_JWE_DECRYPTER_FACTORY_EXCEPTION; 258 } 259 260 List<? extends Key> keyCandidates = getJWEKeySelector().selectJWEKeys(jweObject.getHeader(), context); 261 262 if (keyCandidates == null || keyCandidates.isEmpty()) { 263 throw NO_JWE_KEY_CANDIDATES_EXCEPTION; 264 } 265 266 ListIterator<? extends Key> it = keyCandidates.listIterator(); 267 268 while (it.hasNext()) { 269 270 JWEDecrypter decrypter = getJWEDecrypterFactory().createJWEDecrypter(jweObject.getHeader(), it.next()); 271 272 if (decrypter == null) { 273 continue; 274 } 275 276 try { 277 jweObject.decrypt(decrypter); 278 279 } catch (JOSEException e) { 280 281 if (it.hasNext()) { 282 // Try next key 283 continue; 284 } 285 286 // No more keys to try 287 throw new BadJWEException("JWE object rejected: " + e.getMessage(), e); 288 } 289 290 if ("JWT".equalsIgnoreCase(jweObject.getHeader().getContentType())) { 291 292 // Handle nested signed JWT, see http://tools.ietf.org/html/rfc7519#section-5.2 293 JWSObject nestedJWS = jweObject.getPayload().toJWSObject(); 294 295 if (nestedJWS == null) { 296 // Cannot parse payload to JWS object, return original form 297 return jweObject.getPayload(); 298 } 299 300 return process(nestedJWS, context); 301 } 302 303 return jweObject.getPayload(); 304 } 305 306 throw NO_MATCHING_DECRYPTERS_EXCEPTION; 307 } 308}