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