001package com.nimbusds.oauth2.sdk.jose.jwk;
002
003
004import java.security.Key;
005import java.security.PrivateKey;
006import java.util.Collections;
007import java.util.LinkedList;
008import java.util.List;
009
010import com.nimbusds.jose.EncryptionMethod;
011import com.nimbusds.jose.JWEAlgorithm;
012import com.nimbusds.jose.JWEHeader;
013import com.nimbusds.jose.jwk.*;
014import com.nimbusds.jose.proc.JWEKeySelector;
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 decrypting JWE objects used in OpenID Connect.
022 *
023 * <p>Can be used to select RSA and EC key candidates for the decryption of:
024 *
025 * <ul>
026 *     <li>Encrypted ID tokens
027 *     <li>Encrypted JWT-encoded UserInfo responses
028 *     <li>Encrypted OpenID request objects
029 * </ul>
030 */
031@ThreadSafe
032@Deprecated
033public class JWEDecryptionKeySelector extends AbstractJWKSelectorWithSource implements JWEKeySelector {
034
035
036        /**
037         * The expected JWE algorithm.
038         */
039        private final JWEAlgorithm jweAlg;
040
041
042        /**
043         * The expected JWE encryption method.
044         */
045        private final EncryptionMethod jweEnc;
046
047
048        /**
049         * Ensures the specified JWE algorithm is RSA or EC based.
050         *
051         * @param jweAlg The JWE algorithm to check.
052         */
053        private static void ensureAsymmetricEncryptionAlgorithm(final JWEAlgorithm jweAlg) {
054
055                if (! JWEAlgorithm.Family.RSA.contains(jweAlg) && ! JWEAlgorithm.Family.ECDH_ES.contains(jweAlg)) {
056                        throw new IllegalArgumentException("The JWE algorithm must be RSA or EC based");
057                }
058        }
059
060
061        /**
062         * Creates a new decryption key selector.
063         *
064         * @param id        Identifier for the JWE recipient, typically an
065         *                  OAuth 2.0 server issuer ID, or client ID. Must not
066         *                  be {@code null}.
067         * @param jweAlg    The expected JWE algorithm for the objects to be
068         *                  decrypted. Must not be {@code null}.
069         * @param jweEnc    The expected JWE encryption method for the objects
070         *                  to be decrypted. Must be RSA or EC based. Must not
071         *                  be {@code null}.
072         * @param jwkSource The JWK source. Must include the private keys and
073         *                  must not be {@code null}.
074         */
075        public JWEDecryptionKeySelector(final Identifier id,
076                                        final JWEAlgorithm jweAlg,
077                                        final EncryptionMethod jweEnc,
078                                        final JWKSource jwkSource) {
079                super(id, jwkSource);
080                if (jweAlg == null) {
081                        throw new IllegalArgumentException("The JWE algorithm must not be null");
082                }
083                ensureAsymmetricEncryptionAlgorithm(jweAlg);
084                this.jweAlg = jweAlg;
085                if (jweEnc == null) {
086                        throw new IllegalArgumentException("The JWE encryption method must not be null");
087                }
088                this.jweEnc = jweEnc;
089        }
090
091
092        /**
093         * Returns the expected JWE algorithm.
094         *
095         * @return The expected JWE algorithm.
096         */
097        public JWEAlgorithm getExpectedJWEAlgorithm() {
098                return jweAlg;
099        }
100
101
102        /**
103         * The expected JWE encryption method.
104         *
105         * @return The expected JWE encryption method.
106         */
107        public EncryptionMethod getExpectedJWEEncryptionMethod() {
108                return jweEnc;
109        }
110
111
112        /**
113         * Creates a JWK matcher for the expected JWE algorithms and the
114         * specified JWE header.
115         *
116         * @param jweHeader The JWE header. Must not be {@code null}.
117         *
118         * @return The JWK matcher, {@code null} if none could be created.
119         */
120        protected JWKMatcher createJWKMatcher(final JWEHeader jweHeader) {
121
122                if (! getExpectedJWEAlgorithm().equals(jweHeader.getAlgorithm())) {
123                        return null;
124                }
125
126                if (! getExpectedJWEEncryptionMethod().equals(jweHeader.getEncryptionMethod())) {
127                        return null;
128                }
129
130                return new JWKMatcher.Builder()
131                        .keyType(KeyType.forAlgorithm(getExpectedJWEAlgorithm()))
132                        .keyID(jweHeader.getKeyID())
133                        .keyUses(KeyUse.ENCRYPTION, null)
134                        .algorithms(getExpectedJWEAlgorithm(), null)
135                        .build();
136        }
137
138
139        @Override
140        public List<Key> selectJWEKeys(final JWEHeader jweHeader, final SecurityContext context) {
141
142                if (! jweAlg.equals(jweHeader.getAlgorithm()) || ! jweEnc.equals(jweHeader.getEncryptionMethod())) {
143                        // Unexpected JWE alg or enc
144                        return Collections.emptyList();
145                }
146
147                JWKMatcher jwkMatcher = createJWKMatcher(jweHeader);
148                List<JWK> jwkMatches = getJWKSource().get(getIdentifier(), new JWKSelector(jwkMatcher));
149
150                List<Key> sanitizedKeyList = new LinkedList<>();
151
152                for (Key key: KeyConverter.toJavaKeys(jwkMatches)) {
153                        if (key instanceof PrivateKey) {
154                                sanitizedKeyList.add(key);
155                        } // skip public keys
156                }
157
158                return sanitizedKeyList;
159        }
160}