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