001package com.nimbusds.jose.crypto;
002
003
004import java.util.HashSet;
005import java.util.Set;
006
007import net.jcip.annotations.ThreadSafe;
008
009import com.nimbusds.jose.*;
010import com.nimbusds.jose.util.Base64URL;
011
012
013/**
014 * Message Authentication Code (MAC) verifier of 
015 * {@link com.nimbusds.jose.JWSObject JWS objects}. This class is thread-safe.
016 *
017 * <p>Supports the following JSON Web Algorithms (JWAs):
018 *
019 * <ul>
020 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS256}
021 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS384}
022 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS512}
023 * </ul>
024 *
025 * <p>Accepts all {@link com.nimbusds.jose.JWSHeader#getRegisteredParameterNames
026 * registered JWS header parameters}. Use {@link #setAcceptedAlgorithms} to
027 * restrict the acceptable JWS algorithms.
028 * 
029 * @author Vladimir Dzhuvinov
030 * @version $version$ (2014-09-01)
031 */
032@ThreadSafe
033public class MACVerifier extends MACProvider implements JWSVerifier {
034
035
036        /**
037         * The accepted JWS algorithms.
038         */
039        private Set<JWSAlgorithm> acceptedAlgs =
040                new HashSet<>(supportedAlgorithms());
041
042
043        /**
044         * The critical header parameter checker.
045         */
046        private final CriticalHeaderParameterChecker critParamChecker =
047                new CriticalHeaderParameterChecker();
048
049
050        /**
051         * Creates a new Message Authentication (MAC) verifier.
052         *
053         * @param sharedSecret The shared secret. Must not be {@code null}.
054         */
055        public MACVerifier(final byte[] sharedSecret) {
056
057                super(sharedSecret);
058        }
059
060
061        /**
062         * Creates a new Message Authentication (MAC) verifier.
063         *
064         * @param sharedSecretString The shared secret as a UTF-8 encoded
065         *                           string. Must not be {@code null}.
066         */
067        public MACVerifier(final String sharedSecretString) {
068
069                super(sharedSecretString);
070        }
071
072
073        @Override
074        public Set<JWSAlgorithm> getAcceptedAlgorithms() {
075
076                return acceptedAlgs;
077        }
078
079
080        @Override
081        public void setAcceptedAlgorithms(final Set<JWSAlgorithm> acceptedAlgs) {
082
083                if (acceptedAlgs == null) {
084                        throw new IllegalArgumentException("The accepted JWS algorithms must not be null");
085                }
086
087                if (! supportedAlgorithms().containsAll(acceptedAlgs)) {
088                        throw new IllegalArgumentException("Unsupported JWS algorithm(s)");
089                }
090
091                this.acceptedAlgs = acceptedAlgs;
092        }
093
094
095        @Override
096        public Set<String> getIgnoredCriticalHeaderParameters() {
097
098                return critParamChecker.getIgnoredCriticalHeaders();
099        }
100
101
102        @Override
103        public void setIgnoredCriticalHeaderParameters(final Set<String> headers) {
104
105                critParamChecker.setIgnoredCriticalHeaders(headers);
106        }
107
108
109        @Override
110        public boolean verify(final JWSHeader header,
111                              final byte[] signedContent, 
112                              final Base64URL signature)
113                throws JOSEException {
114
115                String jcaAlg = getJCAAlgorithmName(header.getAlgorithm());
116
117                if (! critParamChecker.headerPasses(header)) {
118                        return false;
119                }
120
121                byte[] expectedHMAC = HMAC.compute(jcaAlg, getSharedSecret(), signedContent, provider);
122                return ConstantTimeUtils.areEqual(expectedHMAC, signature.decode());
123        }
124}