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.PublicKey;
023import java.util.Collections;
024import java.util.LinkedList;
025import java.util.List;
026import javax.crypto.SecretKey;
027
028import com.nimbusds.jose.JWSAlgorithm;
029import com.nimbusds.jose.JWSHeader;
030import com.nimbusds.jose.jwk.*;
031import com.nimbusds.jose.proc.JWSKeySelector;
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 verifying JWS objects used in OpenID Connect.
039 *
040 * <p>Can be used to select RSA and EC key candidates for the verification of:
041 *
042 * <ul>
043 *     <li>Signed ID tokens
044 *     <li>Signed JWT-encoded UserInfo responses
045 *     <li>Signed OpenID request objects
046 * </ul>
047 *
048 * <p>Client secret candidates for the verification of:
049 *
050 * <ul>
051 *     <li>HMAC ID tokens
052 *     <li>HMAC JWT-encoded UserInfo responses
053 *     <li>HMAC OpenID request objects
054 * </ul>
055 */
056@ThreadSafe
057@Deprecated
058public class JWSVerificationKeySelector extends AbstractJWKSelectorWithSource implements JWSKeySelector {
059
060
061        /**
062         * The expected JWS algorithm.
063         */
064        private final JWSAlgorithm jwsAlg;
065
066
067        /**
068         * Creates a new JWS verification key selector.
069         *
070         * @param id        Identifier for the JWS originator, typically an
071         *                  OAuth 2.0 server issuer ID, or client ID. Must not
072         *                  be {@code null}.
073         * @param jwsAlg    The expected JWS algorithm for the objects to be
074         *                  verified. Must not be {@code null}.
075         * @param jwkSource The JWK source. Must not be {@code null}.
076         */
077        public JWSVerificationKeySelector(final Identifier id, final JWSAlgorithm jwsAlg, final JWKSource jwkSource) {
078                super(id, jwkSource);
079                if (jwsAlg == null) {
080                        throw new IllegalArgumentException("The JWS algorithm must not be null");
081                }
082                this.jwsAlg = jwsAlg;
083        }
084
085
086        /**
087         * Returns the expected JWS algorithm.
088         *
089         * @return The expected JWS algorithm.
090         */
091        public JWSAlgorithm getExpectedJWSAlgorithm() {
092
093                return jwsAlg;
094        }
095
096
097        /**
098         * Creates a JWK matcher for the expected JWS algorithm and the
099         * specified JWS header.
100         *
101         * @param jwsHeader The JWS header. Must not be {@code null}.
102         *
103         * @return The JWK matcher, {@code null} if none could be created.
104         */
105        protected JWKMatcher createJWKMatcher(final JWSHeader jwsHeader) {
106
107                if (! getExpectedJWSAlgorithm().equals(jwsHeader.getAlgorithm())) {
108                        // Unexpected JWS alg
109                        return null;
110                } else if (JWSAlgorithm.Family.RSA.contains(getExpectedJWSAlgorithm()) || JWSAlgorithm.Family.EC.contains(getExpectedJWSAlgorithm())) {
111                        // RSA or EC key matcher
112                        return new JWKMatcher.Builder()
113                                        .keyType(KeyType.forAlgorithm(getExpectedJWSAlgorithm()))
114                                        .keyID(jwsHeader.getKeyID())
115                                        .keyUses(KeyUse.SIGNATURE, null)
116                                        .algorithms(getExpectedJWSAlgorithm(), null)
117                                        .build();
118                } else if (JWSAlgorithm.Family.HMAC_SHA.contains(getExpectedJWSAlgorithm())) {
119                        // Client secret matcher
120                        return new JWKMatcher.Builder()
121                                        .keyType(KeyType.forAlgorithm(getExpectedJWSAlgorithm()))
122                                        .keyID(jwsHeader.getKeyID())
123                                        .privateOnly(true)
124                                        .algorithms(getExpectedJWSAlgorithm(), null)
125                                        .build();
126                } else {
127                        return null; // Unsupported algorithm
128                }
129        }
130
131
132        @Override
133        public List<Key> selectJWSKeys(final JWSHeader jwsHeader, final SecurityContext context) {
134
135                if (! jwsAlg.equals(jwsHeader.getAlgorithm())) {
136                        // Unexpected JWS alg
137                        return Collections.emptyList();
138                }
139
140                JWKMatcher jwkMatcher = createJWKMatcher(jwsHeader);
141                if (jwkMatcher == null) {
142                        return Collections.emptyList();
143                }
144
145                List<JWK> jwkMatches = getJWKSource().get(getIdentifier(), new JWKSelector(jwkMatcher));
146
147                List<Key> sanitizedKeyList = new LinkedList<>();
148
149                for (Key key: KeyConverter.toJavaKeys(jwkMatches)) {
150                        if (key instanceof PublicKey || key instanceof SecretKey) {
151                                sanitizedKeyList.add(key);
152                        } // skip asymmetric private keys
153                }
154
155                return sanitizedKeyList;
156        }
157}