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