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.EncryptionMethod;
022import com.nimbusds.jose.JWEAlgorithm;
023import com.nimbusds.jose.JWEHeader;
024import com.nimbusds.jose.KeySourceException;
025import com.nimbusds.jose.jwk.JWK;
026import com.nimbusds.jose.jwk.JWKMatcher;
027import com.nimbusds.jose.jwk.JWKSelector;
028import com.nimbusds.jose.jwk.KeyConverter;
029import com.nimbusds.jose.jwk.source.JWKSource;
030import net.jcip.annotations.ThreadSafe;
031
032import javax.crypto.SecretKey;
033import java.security.Key;
034import java.security.PrivateKey;
035import java.util.Collections;
036import java.util.LinkedList;
037import java.util.List;
038import java.util.Objects;
039
040
041/**
042 * Key selector for decrypting JWE objects, where the key candidates are
043 * retrieved from a {@link JWKSource JSON Web Key (JWK) source}.
044 *
045 * @author Vladimir Dzhuvinov
046 * @version 2024-04-20
047 */
048@ThreadSafe
049public class JWEDecryptionKeySelector<C extends SecurityContext> extends AbstractJWKSelectorWithSource<C> implements JWEKeySelector<C> {
050
051
052        /**
053         * The expected JWE algorithm.
054         */
055        private final JWEAlgorithm jweAlg;
056
057
058        /**
059         * The expected JWE encryption method.
060         */
061        private final EncryptionMethod jweEnc;
062
063
064        /**
065         * Creates a new decryption key selector.
066         *
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 not be {@code null}.
071         * @param jwkSource The JWK source. Must include the private keys and
072         *                  must not be {@code null}.
073         */
074        public JWEDecryptionKeySelector(final JWEAlgorithm jweAlg,
075                                        final EncryptionMethod jweEnc,
076                                        final JWKSource<C> jwkSource) {
077                super(jwkSource);
078                this.jweAlg = Objects.requireNonNull(jweAlg);
079                this.jweEnc = Objects.requireNonNull(jweEnc);
080        }
081
082
083        /**
084         * Returns the expected JWE algorithm.
085         *
086         * @return The expected JWE algorithm.
087         */
088        public JWEAlgorithm getExpectedJWEAlgorithm() {
089                return jweAlg;
090        }
091
092
093        /**
094         * The expected JWE encryption method.
095         *
096         * @return The expected JWE encryption method.
097         */
098        public EncryptionMethod getExpectedJWEEncryptionMethod() {
099                return jweEnc;
100        }
101
102
103        /**
104         * Creates a JWK matcher for the expected JWE algorithms and the
105         * specified JWE header.
106         *
107         * @param jweHeader The JWE header. Must not be {@code null}.
108         *
109         * @return The JWK matcher, {@code null} if none could be created.
110         */
111        protected JWKMatcher createJWKMatcher(final JWEHeader jweHeader) {
112
113                if (! getExpectedJWEAlgorithm().equals(jweHeader.getAlgorithm())) {
114                        return null;
115                }
116
117                if (! getExpectedJWEEncryptionMethod().equals(jweHeader.getEncryptionMethod())) {
118                        return null;
119                }
120
121                return JWKMatcher.forJWEHeader(jweHeader);
122        }
123
124
125        @Override
126        public List<Key> selectJWEKeys(final JWEHeader jweHeader, final C context)
127                throws KeySourceException {
128
129                if (! jweAlg.equals(jweHeader.getAlgorithm()) || ! jweEnc.equals(jweHeader.getEncryptionMethod())) {
130                        // Unexpected JWE alg or enc
131                        return Collections.emptyList();
132                }
133
134                JWKMatcher jwkMatcher = createJWKMatcher(jweHeader);
135                List<JWK> jwkMatches = getJWKSource().get(new JWKSelector(jwkMatcher), context);
136                List<Key> sanitizedKeyList = new LinkedList<>();
137
138                for (Key key: KeyConverter.toJavaKeys(jwkMatches)) {
139                        if (key instanceof PrivateKey || key instanceof SecretKey) {
140                                sanitizedKeyList.add(key);
141                        } // skip public keys
142                }
143
144                return sanitizedKeyList;
145        }
146}