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