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.crypto;
019
020
021import java.security.InvalidKeyException;
022import java.security.Signature;
023import java.security.SignatureException;
024import java.security.interfaces.RSAPublicKey;
025import java.util.Set;
026
027import net.jcip.annotations.ThreadSafe;
028
029import com.nimbusds.jose.*;
030import com.nimbusds.jose.jwk.RSAKey;
031import com.nimbusds.jose.util.Base64URL;
032
033
034/**
035 * RSA Signature-Scheme-with-Appendix (RSASSA) verifier of 
036 * {@link com.nimbusds.jose.JWSObject JWS objects}. Expects a public RSA key.
037 *
038 * <p>See RFC 7518, sections
039 * <a href="https://tools.ietf.org/html/rfc7518#section-3.3">3.3</a> and
040 * <a href="https://tools.ietf.org/html/rfc7518#section-3.5">3.5</a> for more
041 * information.
042 *
043 * <p>This class is thread-safe.
044 *
045 * <p>Supports the following algorithms:
046 *
047 * <ul>
048 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS256}
049 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS384}
050 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS512}
051 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS256}
052 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS384}
053 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS512}
054 * </ul>
055 * 
056 * @author Vladimir Dzhuvinov
057 * @version 2015-06-02
058 */
059@ThreadSafe
060public class RSASSAVerifier extends RSASSAProvider implements JWSVerifier, CriticalHeaderParamsAware {
061
062
063        /**
064         * The critical header policy.
065         */
066        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
067
068
069        /**
070         * The public RSA key.
071         */
072        private final RSAPublicKey publicKey;
073
074
075        /**
076         * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) verifier.
077         *
078         * @param publicKey The public RSA key. Must not be {@code null}.
079         */
080        public RSASSAVerifier(final RSAPublicKey publicKey) {
081
082                this(publicKey, null);
083        }
084
085
086        /**
087         * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) verifier.
088         *
089         * @param rsaJWK The RSA JSON Web Key (JWK). Must not be {@code null}.
090         *
091         * @throws JOSEException If the RSA JWK extraction failed.
092         */
093        public RSASSAVerifier(final RSAKey rsaJWK)
094                throws JOSEException {
095
096                this(rsaJWK.toRSAPublicKey(), null);
097        }
098
099
100        /**
101         * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) verifier.
102         *
103         * @param publicKey      The public RSA key. Must not be {@code null}.
104         * @param defCritHeaders The names of the critical header parameters
105         *                       that are deferred to the application for
106         *                       processing, empty set or {@code null} if none.
107         */
108        public RSASSAVerifier(final RSAPublicKey publicKey,
109                              final Set<String> defCritHeaders) {
110
111                if (publicKey == null) {
112                        throw new IllegalArgumentException("The public RSA key must not be null");
113                }
114
115                this.publicKey = publicKey;
116
117                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
118        }
119
120
121        /**
122         * Gets the public RSA key.
123         *
124         * @return The public RSA key.
125         */
126        public RSAPublicKey getPublicKey() {
127
128                return publicKey;
129        }
130
131
132        @Override
133        public Set<String> getProcessedCriticalHeaderParams() {
134
135                return critPolicy.getProcessedCriticalHeaderParams();
136        }
137
138
139        @Override
140        public Set<String> getDeferredCriticalHeaderParams() {
141
142                return critPolicy.getProcessedCriticalHeaderParams();
143        }
144
145
146        @Override
147        public boolean verify(final JWSHeader header,
148                              final byte[] signedContent, 
149                              final Base64URL signature)
150                throws JOSEException {
151
152                if (! critPolicy.headerPasses(header)) {
153                        return false;
154                }
155
156                final Signature verifier = RSASSA.getSignerAndVerifier(header.getAlgorithm(), getJCAContext().getProvider());
157
158                try {
159                        verifier.initVerify(publicKey);
160
161                } catch (InvalidKeyException e) {
162                        throw new JOSEException("Invalid public RSA key: " + e.getMessage(), e);
163                }
164
165                try {
166                        verifier.update(signedContent);
167                        return verifier.verify(signature.decode());
168
169                } catch (SignatureException e) {
170                        return false;
171                }
172        }
173}