001package com.nimbusds.oauth2.sdk.jose.jwk; 002 003 004import java.security.Key; 005import java.security.PublicKey; 006import java.util.Collections; 007import java.util.LinkedList; 008import java.util.List; 009import javax.crypto.SecretKey; 010 011import com.nimbusds.jose.JWSAlgorithm; 012import com.nimbusds.jose.JWSHeader; 013import com.nimbusds.jose.jwk.*; 014import com.nimbusds.jose.proc.JWSKeySelector; 015import com.nimbusds.jose.proc.SecurityContext; 016import com.nimbusds.oauth2.sdk.id.Identifier; 017import net.jcip.annotations.ThreadSafe; 018 019 020/** 021 * Key selector for verifying JWS objects used in OpenID Connect. 022 * 023 * <p>Can be used to select RSA and EC key candidates for the verification of: 024 * 025 * <ul> 026 * <li>Signed ID tokens 027 * <li>Signed JWT-encoded UserInfo responses 028 * <li>Signed OpenID request objects 029 * </ul> 030 * 031 * <p>Client secret candidates for the verification of: 032 * 033 * <ul> 034 * <li>HMAC ID tokens 035 * <li>HMAC JWT-encoded UserInfo responses 036 * <li>HMAC OpenID request objects 037 * </ul> 038 */ 039@ThreadSafe 040@Deprecated 041public class JWSVerificationKeySelector extends AbstractJWKSelectorWithSource implements JWSKeySelector { 042 043 044 /** 045 * The expected JWS algorithm. 046 */ 047 private final JWSAlgorithm jwsAlg; 048 049 050 /** 051 * Creates a new JWS verification key selector. 052 * 053 * @param id Identifier for the JWS originator, typically an 054 * OAuth 2.0 server issuer ID, or client ID. Must not 055 * be {@code null}. 056 * @param jwsAlg The expected JWS algorithm for the objects to be 057 * verified. Must not be {@code null}. 058 * @param jwkSource The JWK source. Must not be {@code null}. 059 */ 060 public JWSVerificationKeySelector(final Identifier id, final JWSAlgorithm jwsAlg, final JWKSource jwkSource) { 061 super(id, jwkSource); 062 if (jwsAlg == null) { 063 throw new IllegalArgumentException("The JWS algorithm must not be null"); 064 } 065 this.jwsAlg = jwsAlg; 066 } 067 068 069 /** 070 * Returns the expected JWS algorithm. 071 * 072 * @return The expected JWS algorithm. 073 */ 074 public JWSAlgorithm getExpectedJWSAlgorithm() { 075 076 return jwsAlg; 077 } 078 079 080 /** 081 * Creates a JWK matcher for the expected JWS algorithm and the 082 * specified JWS header. 083 * 084 * @param jwsHeader The JWS header. Must not be {@code null}. 085 * 086 * @return The JWK matcher, {@code null} if none could be created. 087 */ 088 protected JWKMatcher createJWKMatcher(final JWSHeader jwsHeader) { 089 090 if (! getExpectedJWSAlgorithm().equals(jwsHeader.getAlgorithm())) { 091 // Unexpected JWS alg 092 return null; 093 } else if (JWSAlgorithm.Family.RSA.contains(getExpectedJWSAlgorithm()) || JWSAlgorithm.Family.EC.contains(getExpectedJWSAlgorithm())) { 094 // RSA or EC key matcher 095 return new JWKMatcher.Builder() 096 .keyType(KeyType.forAlgorithm(getExpectedJWSAlgorithm())) 097 .keyID(jwsHeader.getKeyID()) 098 .keyUses(KeyUse.SIGNATURE, null) 099 .algorithms(getExpectedJWSAlgorithm(), null) 100 .build(); 101 } else if (JWSAlgorithm.Family.HMAC_SHA.contains(getExpectedJWSAlgorithm())) { 102 // Client secret matcher 103 return new JWKMatcher.Builder() 104 .keyType(KeyType.forAlgorithm(getExpectedJWSAlgorithm())) 105 .keyID(jwsHeader.getKeyID()) 106 .privateOnly(true) 107 .algorithms(getExpectedJWSAlgorithm(), null) 108 .build(); 109 } else { 110 return null; // Unsupported algorithm 111 } 112 } 113 114 115 @Override 116 public List<Key> selectJWSKeys(final JWSHeader jwsHeader, final SecurityContext context) { 117 118 if (! jwsAlg.equals(jwsHeader.getAlgorithm())) { 119 // Unexpected JWS alg 120 return Collections.emptyList(); 121 } 122 123 JWKMatcher jwkMatcher = createJWKMatcher(jwsHeader); 124 if (jwkMatcher == null) { 125 return Collections.emptyList(); 126 } 127 128 List<JWK> jwkMatches = getJWKSource().get(getIdentifier(), new JWKSelector(jwkMatcher)); 129 130 List<Key> sanitizedKeyList = new LinkedList<>(); 131 132 for (Key key: KeyConverter.toJavaKeys(jwkMatches)) { 133 if (key instanceof PublicKey || key instanceof SecretKey) { 134 sanitizedKeyList.add(key); 135 } // skip asymmetric private keys 136 } 137 138 return sanitizedKeyList; 139 } 140}