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