001package com.nimbusds.jose.proc;
002
003
004import java.io.IOException;
005import java.security.Key;
006import java.security.PrivateKey;
007import java.util.Collections;
008import java.util.LinkedList;
009import java.util.List;
010
011import javax.crypto.SecretKey;
012
013import com.nimbusds.jose.EncryptionMethod;
014import com.nimbusds.jose.JWEAlgorithm;
015import com.nimbusds.jose.JWEHeader;
016import com.nimbusds.jose.jwk.*;
017import com.nimbusds.jose.jwk.source.JWKSource;
018import net.jcip.annotations.ThreadSafe;
019
020
021/**
022 * Key selector for decrypting JWE objects, where the key candidates are
023 * retrieved from a {@link JWKSource JSON Web Key (JWK) source}.
024 *
025 * @author Vladimir Dzhuvinov
026 * @version 2016-06-15
027 */
028@ThreadSafe
029public class JWEDecryptionKeySelector<C extends SecurityContext> extends AbstractJWKSelectorWithSource<C> implements JWEKeySelector<C> {
030
031
032        /**
033         * The expected JWE algorithm.
034         */
035        private final JWEAlgorithm jweAlg;
036
037
038        /**
039         * The expected JWE encryption method.
040         */
041        private final EncryptionMethod jweEnc;
042
043
044        /**
045         * Creates a new decryption key selector.
046         *
047         * @param jweAlg    The expected JWE algorithm for the objects to be
048         *                  decrypted. Must not be {@code null}.
049         * @param jweEnc    The expected JWE encryption method for the objects
050         *                  to be decrypted. Must not be {@code null}.
051         * @param jwkSource The JWK source. Must include the private keys and
052         *                  must not be {@code null}.
053         */
054        public JWEDecryptionKeySelector(final JWEAlgorithm jweAlg,
055                                        final EncryptionMethod jweEnc,
056                                        final JWKSource<C> jwkSource) {
057                super(jwkSource);
058                if (jweAlg == null) {
059                        throw new IllegalArgumentException("The JWE algorithm must not be null");
060                }
061                this.jweAlg = jweAlg;
062                if (jweEnc == null) {
063                        throw new IllegalArgumentException("The JWE encryption method must not be null");
064                }
065                this.jweEnc = jweEnc;
066        }
067
068
069        /**
070         * Returns the expected JWE algorithm.
071         *
072         * @return The expected JWE algorithm.
073         */
074        public JWEAlgorithm getExpectedJWEAlgorithm() {
075                return jweAlg;
076        }
077
078
079        /**
080         * The expected JWE encryption method.
081         *
082         * @return The expected JWE encryption method.
083         */
084        public EncryptionMethod getExpectedJWEEncryptionMethod() {
085                return jweEnc;
086        }
087
088
089        /**
090         * Creates a JWK matcher for the expected JWE algorithms and the
091         * specified JWE header.
092         *
093         * @param jweHeader The JWE header. Must not be {@code null}.
094         *
095         * @return The JWK matcher, {@code null} if none could be created.
096         */
097        protected JWKMatcher createJWKMatcher(final JWEHeader jweHeader) {
098
099                if (! getExpectedJWEAlgorithm().equals(jweHeader.getAlgorithm())) {
100                        return null;
101                }
102
103                if (! getExpectedJWEEncryptionMethod().equals(jweHeader.getEncryptionMethod())) {
104                        return null;
105                }
106
107                return new JWKMatcher.Builder()
108                        .keyType(KeyType.forAlgorithm(getExpectedJWEAlgorithm()))
109                        .keyID(jweHeader.getKeyID())
110                        .keyUses(KeyUse.ENCRYPTION, null)
111                        .algorithms(getExpectedJWEAlgorithm(), null)
112                        .build();
113        }
114
115
116        @Override
117        public List<Key> selectJWEKeys(final JWEHeader jweHeader, final C context)
118                throws IOException {
119
120                if (! jweAlg.equals(jweHeader.getAlgorithm()) || ! jweEnc.equals(jweHeader.getEncryptionMethod())) {
121                        // Unexpected JWE alg or enc
122                        return Collections.emptyList();
123                }
124
125                JWKMatcher jwkMatcher = createJWKMatcher(jweHeader);
126                List<JWK> jwkMatches = getJWKSource().get(new JWKSelector(jwkMatcher), context);
127                List<Key> sanitizedKeyList = new LinkedList<>();
128
129                for (Key key: KeyConverter.toJavaKeys(jwkMatches)) {
130                        if (key instanceof PrivateKey || key instanceof SecretKey) {
131                                sanitizedKeyList.add(key);
132                        } // skip public keys
133                }
134
135                return sanitizedKeyList;
136        }
137}