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 com.nimbusds.jose.JWSAlgorithm; 022import com.nimbusds.jose.JWSHeader; 023import com.nimbusds.jose.KeySourceException; 024import com.nimbusds.jose.jwk.*; 025import com.nimbusds.jose.jwk.source.JWKSource; 026import com.nimbusds.jose.jwk.source.RemoteJWKSet; 027 028import java.net.URL; 029import java.security.Key; 030import java.util.Collections; 031import java.util.HashMap; 032import java.util.List; 033import java.util.Map; 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 for (JWSAlgorithm jwsAlg : jwsAlgFamily) { 059 this.selectors.put(jwsAlg, new JWSVerificationKeySelector<>(jwsAlg, jwkSource)); 060 } 061 } 062 063 064 @Override 065 public List<? extends Key> selectJWSKeys(final JWSHeader header, final C context) 066 throws KeySourceException { 067 068 JWSKeySelector<C> selector = this.selectors.get(header.getAlgorithm()); 069 if (selector == null) { 070 return Collections.emptyList(); 071 } 072 return selector.selectJWSKeys(header, context); 073 } 074 075 076 /** 077 * Queries the given JWK Set {@link URL} for keys, creating a 078 * {@link JWSAlgorithmFamilyJWSKeySelector} based on the RSA or EC key 079 * type, whichever comes back first. 080 * 081 * @param jwkSetURL The JWK Set {@link URL} to query. 082 * @param <C> The {@link SecurityContext} 083 * 084 * @return An instance of {@link JWSAlgorithmFamilyJWSKeySelector}. 085 * 086 * @throws KeySourceException if the JWKs cannot be retrieved or no RSA 087 * or EC public JWKs are found. 088 */ 089 public static <C extends SecurityContext> JWSAlgorithmFamilyJWSKeySelector<C> fromJWKSetURL(final URL jwkSetURL) 090 throws KeySourceException { 091 092 JWKSource<C> jwkSource = new RemoteJWKSet<>(jwkSetURL); 093 return fromJWKSource(jwkSource); 094 } 095 096 097 /** 098 * Queries the given {@link JWKSource} for keys, creating a 099 * {@link JWSAlgorithmFamilyJWSKeySelector} based on the RSA or EC key 100 * type, whichever comes back first. 101 * 102 * @param jwkSource The {@link JWKSource}. 103 * @param <C> The {@link SecurityContext}. 104 * 105 * @return An instance of {@link JWSAlgorithmFamilyJWSKeySelector}. 106 * 107 * @throws KeySourceException If the JWKs cannot be retrieved or no 108 * RSA or EC public JWKs are found. 109 */ 110 public static <C extends SecurityContext> JWSAlgorithmFamilyJWSKeySelector<C> fromJWKSource(final JWKSource<C> jwkSource) 111 throws KeySourceException { 112 113 JWKMatcher jwkMatcher = new JWKMatcher.Builder() 114 .publicOnly(true) 115 .keyUses(KeyUse.SIGNATURE, null) // use=sig is optional 116 .keyTypes(KeyType.RSA, KeyType.EC) 117 .build(); 118 List<? extends JWK> jwks = jwkSource.get(new JWKSelector(jwkMatcher), null); 119 for (JWK jwk : jwks) { 120 if (KeyType.RSA.equals(jwk.getKeyType())) { 121 return new JWSAlgorithmFamilyJWSKeySelector<>(JWSAlgorithm.Family.RSA, jwkSource); 122 } 123 if (KeyType.EC.equals(jwk.getKeyType())) { 124 return new JWSAlgorithmFamilyJWSKeySelector<>(JWSAlgorithm.Family.EC, jwkSource); 125 } 126 } 127 throw new KeySourceException("Couldn't retrieve JWKs"); 128 } 129}