001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2019, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.proc; 019 020 021import java.security.Key; 022import java.text.ParseException; 023import java.util.List; 024import java.util.ListIterator; 025 026import net.jcip.annotations.ThreadSafe; 027 028import com.nimbusds.jose.*; 029import com.nimbusds.jose.crypto.factories.DefaultJWEDecrypterFactory; 030import com.nimbusds.jose.crypto.factories.DefaultJWSVerifierFactory; 031 032 033/** 034 * Default processor of {@link com.nimbusds.jose.PlainObject unsecured} 035 * (plain), {@link com.nimbusds.jose.JWSObject JWS} and 036 * {@link com.nimbusds.jose.JWEObject JWE} objects. 037 * 038 * <p>Must be configured with the following: 039 * 040 * <ul> 041 * <li>To verify JWS objects: A {@link #setJWSKeySelector JWS key selector} 042 * using the header to suggest key candidate(s) for the signature 043 * verification. The key selection procedure is application-specific and 044 * may involve key ID lookup, a certificate check and / or some 045 * {@link SecurityContext context}.</li> 046 * 047 * <li>To decrypt JWE objects: A {@link #setJWEKeySelector JWE key 048 * selector} using the header to suggest key candidate(s) for decryption. 049 * The key selection procedure is application-specific and may involve key 050 * ID lookup, a certificate check and / or some {@link SecurityContext 051 * context}.</li> 052 * </ul> 053 * 054 * <p>An optional {@link SecurityContext context} parameter is available to 055 * facilitate passing of additional data between the caller and the underlying 056 * selector of key candidates (in both directions). 057 * 058 * <p>See sections 6 of RFC 7515 (JWS) and RFC 7516 (JWE) for guidelines on key 059 * selection. 060 * 061 * <p>This processor is configured with a standard header "typ" (type) 062 * parameter {@link DefaultJOSEObjectTypeVerifier#JOSE verifier} which expects 063 * the JWS, JWE and plain (unsecured) objects to have the type header omitted 064 * or set to {@link JOSEObjectType#JOSE JOSE}. To accept other "typ" values 065 * pass an appropriately configured JWS and / or JWE 066 * {@link DefaultJOSEObjectTypeVerifier type verifier}. 067 * 068 * <p>This processor comes with the default {@link DefaultJWSVerifierFactory 069 * JWS verifier factory} and the default {@link DefaultJWEDecrypterFactory 070 * JWE decrypter factory}; they can construct verifiers / decrypters for all 071 * standard JOSE algorithms implemented by the library. 072 * 073 * <p>Note that for security reasons this processor is hardwired to reject 074 * unsecured (plain) JOSE objects. Override the {@link #process(PlainObject, 075 * SecurityContext)} method if you need to handle unsecured JOSE objects. 076 * 077 * <p>To process JSON Web Tokens (JWTs) use the 078 * {@link com.nimbusds.jwt.proc.DefaultJWTProcessor} class. 079 * 080 * @author Vladimir Dzhuvinov 081 * @version 2019-10-15 082 */ 083@ThreadSafe 084public class DefaultJOSEProcessor<C extends SecurityContext> implements ConfigurableJOSEProcessor<C>{ 085 086 /** 087 * The JWS type verifier. 088 */ 089 private JOSEObjectTypeVerifier<C> jwsTypeVerifier = DefaultJOSEObjectTypeVerifier.JOSE; 090 091 092 /** 093 * The JWE type verifier. 094 */ 095 private JOSEObjectTypeVerifier<C> jweTypeVerifier = DefaultJOSEObjectTypeVerifier.JOSE; 096 097 098 /** 099 * The JWS key selector. 100 */ 101 private JWSKeySelector<C> jwsKeySelector; 102 103 104 /** 105 * The JWE key selector. 106 */ 107 private JWEKeySelector<C> jweKeySelector; 108 109 110 /** 111 * The JWS verifier factory. 112 */ 113 private JWSVerifierFactory jwsVerifierFactory = new DefaultJWSVerifierFactory(); 114 115 116 /** 117 * The JWE decrypter factory. 118 */ 119 private JWEDecrypterFactory jweDecrypterFactory = new DefaultJWEDecrypterFactory(); 120 121 122 @Override 123 public JOSEObjectTypeVerifier<C> getJWSTypeVerifier() { 124 125 return jwsTypeVerifier; 126 } 127 128 129 @Override 130 public void setJWSTypeVerifier(final JOSEObjectTypeVerifier<C> jwsTypeVerifier) { 131 132 this.jwsTypeVerifier = jwsTypeVerifier; 133 } 134 135 136 @Override 137 public JWSKeySelector<C> getJWSKeySelector() { 138 139 return jwsKeySelector; 140 } 141 142 143 @Override 144 public void setJWSKeySelector(final JWSKeySelector<C> jwsKeySelector) { 145 146 this.jwsKeySelector = jwsKeySelector; 147 } 148 149 150 @Override 151 public JOSEObjectTypeVerifier<C> getJWETypeVerifier() { 152 153 return jweTypeVerifier; 154 } 155 156 157 @Override 158 public void setJWETypeVerifier(final JOSEObjectTypeVerifier<C> jweTypeVerifier) { 159 160 this.jweTypeVerifier = jweTypeVerifier; 161 } 162 163 164 @Override 165 public JWEKeySelector<C> getJWEKeySelector() { 166 167 return jweKeySelector; 168 } 169 170 171 @Override 172 public void setJWEKeySelector(final JWEKeySelector<C> jweKeySelector) { 173 174 this.jweKeySelector = jweKeySelector; 175 } 176 177 178 @Override 179 public JWSVerifierFactory getJWSVerifierFactory() { 180 181 return jwsVerifierFactory; 182 } 183 184 185 @Override 186 public void setJWSVerifierFactory(final JWSVerifierFactory factory) { 187 188 jwsVerifierFactory = factory; 189 } 190 191 192 @Override 193 public JWEDecrypterFactory getJWEDecrypterFactory() { 194 195 return jweDecrypterFactory; 196 } 197 198 199 @Override 200 public void setJWEDecrypterFactory(final JWEDecrypterFactory factory) { 201 202 jweDecrypterFactory = factory; 203 } 204 205 206 @Override 207 public Payload process(final String compactJOSE, final C context) 208 throws ParseException, BadJOSEException, JOSEException { 209 210 return process(JOSEObject.parse(compactJOSE), context); 211 } 212 213 214 @Override 215 public Payload process(final JOSEObject joseObject, final C context) 216 throws BadJOSEException, JOSEException { 217 218 if (joseObject instanceof JWSObject) { 219 return process((JWSObject)joseObject, context); 220 } 221 222 if (joseObject instanceof JWEObject) { 223 return process((JWEObject)joseObject, context); 224 } 225 226 if (joseObject instanceof PlainObject) { 227 return process((PlainObject)joseObject, context); 228 } 229 230 // Should never happen 231 throw new JOSEException("Unexpected JOSE object type: " + joseObject.getClass()); 232 } 233 234 235 @Override 236 public Payload process(final PlainObject plainObject, C context) 237 throws BadJOSEException { 238 239 // JWS type verifier applies to unsecured JOSE as well 240 if (jwsTypeVerifier == null) { 241 throw new BadJOSEException("Unsecured (plain) JOSE object rejected: No JWS header typ (type) verifier is configured"); 242 } 243 jwsTypeVerifier.verify(plainObject.getHeader().getType(), context); 244 245 throw new BadJOSEException("Unsecured (plain) JOSE objects are rejected, extend class to handle"); 246 } 247 248 249 @Override 250 public Payload process(final JWSObject jwsObject, C context) 251 throws BadJOSEException, JOSEException { 252 253 if (jwsTypeVerifier == null) { 254 throw new BadJOSEException("JWS object rejected: No JWS header typ (type) verifier is configured"); 255 } 256 257 jwsTypeVerifier.verify(jwsObject.getHeader().getType(), context); 258 259 if (getJWSKeySelector() == null) { 260 // JWS key selector may have been deliberately omitted 261 throw new BadJOSEException("JWS object rejected: No JWS key selector is configured"); 262 } 263 264 if (getJWSVerifierFactory() == null) { 265 throw new JOSEException("No JWS verifier is configured"); 266 } 267 268 List<? extends Key> keyCandidates = getJWSKeySelector().selectJWSKeys(jwsObject.getHeader(), context); 269 270 if (keyCandidates == null || keyCandidates.isEmpty()) { 271 throw new BadJOSEException("JWS object rejected: Another algorithm expected, or no matching key(s) found"); 272 } 273 274 ListIterator<? extends Key> it = keyCandidates.listIterator(); 275 276 while (it.hasNext()) { 277 278 JWSVerifier verifier = getJWSVerifierFactory().createJWSVerifier(jwsObject.getHeader(), it.next()); 279 280 if (verifier == null) { 281 continue; 282 } 283 284 final boolean validSignature = jwsObject.verify(verifier); 285 286 if (validSignature) { 287 return jwsObject.getPayload(); 288 } 289 290 if (! it.hasNext()) { 291 // No more keys to try out 292 throw new BadJWSException("JWS object rejected: Invalid signature"); 293 } 294 } 295 296 throw new BadJOSEException("JWS object rejected: No matching verifier(s) found"); 297 } 298 299 300 @Override 301 public Payload process(final JWEObject jweObject, C context) 302 throws BadJOSEException, JOSEException { 303 304 if (jweTypeVerifier == null) { 305 throw new BadJOSEException("JWE object rejected: No JWE header typ (type) verifier is configured"); 306 } 307 308 jweTypeVerifier.verify(jweObject.getHeader().getType(), context); 309 310 if (getJWEKeySelector() == null) { 311 // JWE key selector may have been deliberately omitted 312 throw new BadJOSEException("JWE object rejected: No JWE key selector is configured"); 313 } 314 315 if (getJWEDecrypterFactory() == null) { 316 throw new JOSEException("No JWE decrypter is configured"); 317 } 318 319 List<? extends Key> keyCandidates = getJWEKeySelector().selectJWEKeys(jweObject.getHeader(), context); 320 321 if (keyCandidates == null || keyCandidates.isEmpty()) { 322 throw new BadJOSEException("JWE object rejected: Another algorithm expected, or no matching key(s) found"); 323 } 324 325 ListIterator<? extends Key> it = keyCandidates.listIterator(); 326 327 while (it.hasNext()) { 328 329 JWEDecrypter decrypter = getJWEDecrypterFactory().createJWEDecrypter(jweObject.getHeader(), it.next()); 330 331 if (decrypter == null) { 332 continue; 333 } 334 335 try { 336 jweObject.decrypt(decrypter); 337 338 } catch (JOSEException e) { 339 340 if (it.hasNext()) { 341 // Try next key 342 continue; 343 } 344 345 // No more keys to try 346 throw new BadJWEException("JWE object rejected: " + e.getMessage(), e); 347 } 348 349 if ("JWT".equalsIgnoreCase(jweObject.getHeader().getContentType())) { 350 351 // Handle nested signed JWT, see http://tools.ietf.org/html/rfc7519#section-5.2 352 JWSObject nestedJWS = jweObject.getPayload().toJWSObject(); 353 354 if (nestedJWS == null) { 355 // Cannot parse payload to JWS object, return original form 356 return jweObject.getPayload(); 357 } 358 359 return process(nestedJWS, context); 360 } 361 362 return jweObject.getPayload(); 363 } 364 365 throw new BadJOSEException("JWE object rejected: No matching decrypter(s) found"); 366 } 367}