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