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.net.URL; 022import java.security.Key; 023import java.util.Collections; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027 028import com.nimbusds.jose.JWSAlgorithm; 029import com.nimbusds.jose.JWSHeader; 030import com.nimbusds.jose.KeySourceException; 031import com.nimbusds.jose.jwk.*; 032import com.nimbusds.jose.jwk.source.JWKSource; 033import com.nimbusds.jose.jwk.source.RemoteJWKSet; 034 035/** 036 * A {@link JWSKeySelector} that expects an algorithm from a specified 037 * algorithm family. 038 * 039 * @author Josh Cummings 040 * @since 2019-07-12 041 */ 042public class JWSAlgorithmFamilyJWSKeySelector<C extends SecurityContext> extends AbstractJWKSelectorWithSource<C> implements JWSKeySelector<C> { 043 044 045 private final Map<JWSAlgorithm, JWSKeySelector<C>> selectors = new HashMap<>(); 046 047 048 /** 049 * Creates a {@link JWSKeySelector} that matches any algorithm from the 050 * given {@link JWSAlgorithm.Family}. 051 * 052 * @param jwsAlgFamily The {@link JWSAlgorithm.Family} to use. 053 * @param jwkSource The {@link JWKSource} from which to draw the set 054 * of {@link JWK}s. 055 */ 056 public JWSAlgorithmFamilyJWSKeySelector(final JWSAlgorithm.Family jwsAlgFamily, final JWKSource<C> jwkSource) { 057 super(jwkSource); 058 if (jwsAlgFamily == null) { 059 throw new IllegalArgumentException("JWS algorithm family must not be null"); 060 } 061 for (JWSAlgorithm jwsAlg : jwsAlgFamily) { 062 this.selectors.put(jwsAlg, new JWSVerificationKeySelector<>(jwsAlg, jwkSource)); 063 } 064 } 065 066 067 @Override 068 public List<? extends Key> selectJWSKeys(final JWSHeader header, final C context) 069 throws KeySourceException { 070 071 JWSKeySelector<C> selector = this.selectors.get(header.getAlgorithm()); 072 if (selector == null) { 073 return Collections.emptyList(); 074 } 075 return selector.selectJWSKeys(header, context); 076 } 077 078 079 /** 080 * Queries the given JWK Set {@link URL} for keys, creating a 081 * {@link JWSAlgorithmFamilyJWSKeySelector} based on the RSA or EC key 082 * type, whichever comes back first. 083 * 084 * @param jwkSetURL The JWK Set {@link URL} to query. 085 * @param <C> The {@link SecurityContext} 086 * 087 * @return An instance of {@link JWSAlgorithmFamilyJWSKeySelector}. 088 * 089 * @throws KeySourceException if the JWKs cannot be retrieved or no RSA 090 * or EC public JWKs are found. 091 */ 092 public static <C extends SecurityContext> JWSAlgorithmFamilyJWSKeySelector<C> fromJWKSetURL(final URL jwkSetURL) 093 throws KeySourceException { 094 095 JWKSource<C> jwkSource = new RemoteJWKSet<>(jwkSetURL); 096 return fromJWKSource(jwkSource); 097 } 098 099 100 /** 101 * Queries the given {@link JWKSource} for keys, creating a 102 * {@link JWSAlgorithmFamilyJWSKeySelector} based on the RSA or EC key 103 * type, whichever comes back first. 104 * 105 * @param jwkSource The {@link JWKSource}. 106 * @param <C> The {@link SecurityContext}. 107 * 108 * @return An instance of {@link JWSAlgorithmFamilyJWSKeySelector}. 109 * 110 * @throws KeySourceException If the JWKs cannot be retrieved or no 111 * RSA or EC public JWKs are found. 112 */ 113 public static <C extends SecurityContext> JWSAlgorithmFamilyJWSKeySelector<C> fromJWKSource(final JWKSource<C> jwkSource) 114 throws KeySourceException { 115 116 JWKMatcher jwkMatcher = new JWKMatcher.Builder() 117 .publicOnly(true) 118 .keyUses(KeyUse.SIGNATURE, null) // use=sig is optional 119 .keyTypes(KeyType.RSA, KeyType.EC) 120 .build(); 121 List<? extends JWK> jwks = jwkSource.get(new JWKSelector(jwkMatcher), null); 122 for (JWK jwk : jwks) { 123 if (KeyType.RSA.equals(jwk.getKeyType())) { 124 return new JWSAlgorithmFamilyJWSKeySelector<>(JWSAlgorithm.Family.RSA, jwkSource); 125 } 126 if (KeyType.EC.equals(jwk.getKeyType())) { 127 return new JWSAlgorithmFamilyJWSKeySelector<>(JWSAlgorithm.Family.EC, jwkSource); 128 } 129 } 130 throw new KeySourceException("Couldn't retrieve JWKs"); 131 } 132}