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.HashSet;
009import java.util.Set;
010
011import net.jcip.annotations.ThreadSafe;
012
013import com.nimbusds.jose.JOSEException;
014import com.nimbusds.jose.JWSAlgorithm;
015import com.nimbusds.jose.JWSVerifier;
016import com.nimbusds.jose.JWSHeader;
017import com.nimbusds.jose.util.Base64URL;
018
019
020/**
021 * RSA Signature-Scheme-with-Appendix (RSASSA) verifier of 
022 * {@link com.nimbusds.jose.JWSObject JWS objects}. This class is thread-safe.
023 *
024 * <p>Supports the following JSON Web Algorithms (JWAs):
025 *
026 * <ul>
027 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS256}
028 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS384}
029 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS512}
030 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS256}
031 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS384}
032 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#PS512}
033 * </ul>
034 *
035 * <p>Accepts all {@link com.nimbusds.jose.JWSHeader#getRegisteredParameterNames
036 * registered JWS header parameters}. Use {@link #setAcceptedAlgorithms} to
037 * restrict the acceptable JWS algorithms.
038 * 
039 * @author Vladimir Dzhuvinov
040 * @version $version$ (2014-04-22)
041 */
042@ThreadSafe
043public class RSASSAVerifier extends RSASSAProvider implements JWSVerifier {
044
045
046        /**
047         * The accepted JWS algorithms.
048         */
049        private Set<JWSAlgorithm> acceptedAlgs =
050                new HashSet<>(supportedAlgorithms());
051
052
053        /**
054         * The critical header parameter checker.
055         */
056        private final CriticalHeaderParameterChecker critParamChecker =
057                new CriticalHeaderParameterChecker();
058
059
060        /**
061         * The public RSA key.
062         */
063        private final RSAPublicKey publicKey;
064
065
066        /**
067         * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) verifier.
068         *
069         * @param publicKey The public RSA key. Must not be {@code null}.
070         */
071        public RSASSAVerifier(final RSAPublicKey publicKey) {
072
073                if (publicKey == null) {
074
075                        throw new IllegalArgumentException("The public RSA key must not be null");
076                }
077
078                this.publicKey = publicKey;
079        }
080
081
082        /**
083         * Gets the public RSA key.
084         *
085         * @return The public RSA key.
086         */
087        public RSAPublicKey getPublicKey() {
088
089                return publicKey;
090        }
091
092
093        @Override
094        public Set<JWSAlgorithm> getAcceptedAlgorithms() {
095
096                return acceptedAlgs;
097        }
098
099
100        @Override
101        public void setAcceptedAlgorithms(final Set<JWSAlgorithm> acceptedAlgs) {
102
103                if (acceptedAlgs == null) {
104                        throw new IllegalArgumentException("The accepted JWS algorithms must not be null");
105                }
106
107                if (! supportedAlgorithms().containsAll(acceptedAlgs)) {
108                        throw new IllegalArgumentException("Unsupported JWS algorithm(s)");
109                }
110
111                this.acceptedAlgs = acceptedAlgs;
112        }
113
114
115        @Override
116        public Set<String> getIgnoredCriticalHeaderParameters() {
117
118                return critParamChecker.getIgnoredCriticalHeaders();
119        }
120
121
122        @Override
123        public void setIgnoredCriticalHeaderParameters(final Set<String> headers) {
124
125                critParamChecker.setIgnoredCriticalHeaders(headers);
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 (! critParamChecker.headerPasses(header)) {
136                        return false;
137                }
138
139                Signature verifier = getRSASignerAndVerifier(header.getAlgorithm(), provider);
140
141                try {
142                        verifier.initVerify(publicKey);
143
144                } catch (InvalidKeyException e) {
145
146                        throw new JOSEException("Invalid public RSA key: " + e.getMessage(), e);
147                }
148
149                try {
150                        verifier.update(signedContent);
151                        return verifier.verify(signature.decode());
152
153                } catch (SignatureException e) {
154
155                        return false;
156                }
157        }
158}