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-08-22 055 */ 056@ThreadSafe 057public class DefaultJOSEProcessor<C extends SecurityContext> implements ConfigurableJOSEProcessor<C>{ 058 059 060 /** 061 * The JWS key selector. 062 */ 063 private JWSKeySelector<C> jwsKeySelector; 064 065 066 /** 067 * The JWE key selector. 068 */ 069 private JWEKeySelector<C> jweKeySelector; 070 071 072 /** 073 * The JWS verifier factory. 074 */ 075 private JWSVerifierFactory jwsVerifierFactory = new DefaultJWSVerifierFactory(); 076 077 078 /** 079 * The JWE decrypter factory. 080 */ 081 private JWEDecrypterFactory jweDecrypterFactory = new DefaultJWEDecrypterFactory(); 082 083 084 @Override 085 public JWSKeySelector<C> getJWSKeySelector() { 086 087 return jwsKeySelector; 088 } 089 090 091 @Override 092 public void setJWSKeySelector(final JWSKeySelector<C> jwsKeySelector) { 093 094 this.jwsKeySelector = jwsKeySelector; 095 } 096 097 098 @Override 099 public JWEKeySelector<C> getJWEKeySelector() { 100 101 return jweKeySelector; 102 } 103 104 105 @Override 106 public void setJWEKeySelector(final JWEKeySelector<C> jweKeySelector) { 107 108 this.jweKeySelector = jweKeySelector; 109 } 110 111 112 @Override 113 public JWSVerifierFactory getJWSVerifierFactory() { 114 115 return jwsVerifierFactory; 116 } 117 118 119 @Override 120 public void setJWSVerifierFactory(final JWSVerifierFactory factory) { 121 122 jwsVerifierFactory = factory; 123 } 124 125 126 @Override 127 public JWEDecrypterFactory getJWEDecrypterFactory() { 128 129 return jweDecrypterFactory; 130 } 131 132 133 @Override 134 public void setJWEDecrypterFactory(final JWEDecrypterFactory factory) { 135 136 jweDecrypterFactory = factory; 137 } 138 139 140 @Override 141 public Payload process(final String compactJOSE, final C context) 142 throws ParseException, BadJOSEException, JOSEException { 143 144 return process(JOSEObject.parse(compactJOSE), context); 145 } 146 147 148 @Override 149 public Payload process(final JOSEObject joseObject, final C context) 150 throws BadJOSEException, JOSEException { 151 152 if (joseObject instanceof JWSObject) { 153 return process((JWSObject)joseObject, context); 154 } 155 156 if (joseObject instanceof JWEObject) { 157 return process((JWEObject)joseObject, context); 158 } 159 160 if (joseObject instanceof PlainObject) { 161 return process((PlainObject)joseObject, context); 162 } 163 164 // Should never happen 165 throw new JOSEException("Unexpected JOSE object type: " + joseObject.getClass()); 166 } 167 168 169 @Override 170 public Payload process(final PlainObject plainObject, C context) 171 throws BadJOSEException { 172 173 throw new BadJOSEException("Unsecured (plain) JOSE objects are rejected, extend class to handle"); 174 } 175 176 177 @Override 178 public Payload process(final JWSObject jwsObject, C context) 179 throws BadJOSEException, JOSEException { 180 181 if (getJWSKeySelector() == null) { 182 // JWS key selector may have been deliberately omitted 183 throw new BadJOSEException("JWS object rejected: No JWS key selector is configured"); 184 } 185 186 if (getJWSVerifierFactory() == null) { 187 throw new JOSEException("No JWS verifier is configured"); 188 } 189 190 List<? extends Key> keyCandidates = getJWSKeySelector().selectJWSKeys(jwsObject.getHeader(), context); 191 192 if (keyCandidates == null || keyCandidates.isEmpty()) { 193 throw new BadJOSEException("JWS object rejected: No matching key(s) found"); 194 } 195 196 ListIterator<? extends Key> it = keyCandidates.listIterator(); 197 198 while (it.hasNext()) { 199 200 JWSVerifier verifier = getJWSVerifierFactory().createJWSVerifier(jwsObject.getHeader(), it.next()); 201 202 if (verifier == null) { 203 continue; 204 } 205 206 final boolean validSignature = jwsObject.verify(verifier); 207 208 if (validSignature) { 209 return jwsObject.getPayload(); 210 } 211 212 if (! it.hasNext()) { 213 // No more keys to try out 214 throw new BadJWSException("JWS object rejected: Invalid signature"); 215 } 216 } 217 218 throw new BadJOSEException("JWS object rejected: No matching verifier(s) found"); 219 } 220 221 222 @Override 223 public Payload process(final JWEObject jweObject, C context) 224 throws BadJOSEException, JOSEException { 225 226 if (getJWEKeySelector() == null) { 227 // JWE key selector may have been deliberately omitted 228 throw new BadJOSEException("JWE object rejected: No JWE key selector is configured"); 229 } 230 231 if (getJWEDecrypterFactory() == null) { 232 throw new JOSEException("No JWE decrypter is configured"); 233 } 234 235 List<? extends Key> keyCandidates = getJWEKeySelector().selectJWEKeys(jweObject.getHeader(), context); 236 237 if (keyCandidates == null || keyCandidates.isEmpty()) { 238 throw new BadJOSEException("JWE object rejected: No matching key(s) found"); 239 } 240 241 ListIterator<? extends Key> it = keyCandidates.listIterator(); 242 243 while (it.hasNext()) { 244 245 JWEDecrypter decrypter = getJWEDecrypterFactory().createJWEDecrypter(jweObject.getHeader(), it.next()); 246 247 if (decrypter == null) { 248 continue; 249 } 250 251 try { 252 jweObject.decrypt(decrypter); 253 254 } catch (JOSEException e) { 255 256 if (it.hasNext()) { 257 // Try next key 258 continue; 259 } 260 261 // No more keys to try 262 throw new BadJWEException("JWE object rejected: " + e.getMessage(), e); 263 } 264 265 if ("JWT".equalsIgnoreCase(jweObject.getHeader().getContentType())) { 266 267 // Handle nested signed JWT, see http://tools.ietf.org/html/rfc7519#section-5.2 268 JWSObject nestedJWS = jweObject.getPayload().toJWSObject(); 269 270 if (nestedJWS == null) { 271 // Cannot parse payload to JWS object, return original form 272 return jweObject.getPayload(); 273 } 274 275 return process(nestedJWS, context); 276 } 277 278 return jweObject.getPayload(); 279 } 280 281 throw new BadJOSEException("JWE object rejected: No matching decrypter(s) found"); 282 } 283}