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}