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