001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2016, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.crypto; 019 020 021import com.nimbusds.jose.CriticalHeaderParamsAware; 022import com.nimbusds.jose.JOSEException; 023import com.nimbusds.jose.JWSHeader; 024import com.nimbusds.jose.JWSVerifier; 025import com.nimbusds.jose.crypto.impl.CriticalHeaderParamsDeferral; 026import com.nimbusds.jose.crypto.impl.HMAC; 027import com.nimbusds.jose.crypto.impl.MACProvider; 028import com.nimbusds.jose.crypto.utils.ConstantTimeUtils; 029import com.nimbusds.jose.jwk.OctetSequenceKey; 030import com.nimbusds.jose.util.Base64URL; 031import com.nimbusds.jose.util.ByteUtils; 032import com.nimbusds.jose.util.StandardCharset; 033import net.jcip.annotations.ThreadSafe; 034 035import javax.crypto.SecretKey; 036import java.util.Set; 037 038 039/** 040 * Message Authentication Code (MAC) verifier of 041 * {@link com.nimbusds.jose.JWSObject JWS objects}. Expects a secret key. 042 * 043 * <p>See RFC 7518 044 * <a href="https://tools.ietf.org/html/rfc7518#section-3.2">section 3.2</a> 045 * for more information. 046 * 047 * <p>This class is thread-safe. 048 * 049 * <p>Supports the following algorithms: 050 * 051 * <ul> 052 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS256} 053 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS384} 054 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS512} 055 * </ul> 056 * 057 <p>Tested with the AWS CloudHSM JCE provider. 058 * 059 * @author Vladimir Dzhuvinov 060 * @version 2024-10-28 061 */ 062@ThreadSafe 063public class MACVerifier extends MACProvider implements JWSVerifier, CriticalHeaderParamsAware { 064 065 066 /** 067 * The critical header policy. 068 */ 069 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 070 071 072 /** 073 * Creates a new Message Authentication (MAC) verifier. 074 * 075 * @param secret The secret. Must be at least 256 bits long and not 076 * {@code null}. 077 * 078 * @throws JOSEException If the secret length is shorter than the 079 * minimum 256-bit requirement. 080 */ 081 public MACVerifier(final byte[] secret) 082 throws JOSEException { 083 084 super(secret); 085 } 086 087 088 /** 089 * Creates a new Message Authentication (MAC) verifier. 090 * 091 * @param secretString The secret as a UTF-8 encoded string. Must be at 092 * least 256 bits long and not {@code null}. 093 * 094 * @throws JOSEException If the secret length is shorter than the 095 * minimum 256-bit requirement. 096 */ 097 public MACVerifier(final String secretString) 098 throws JOSEException { 099 100 this(secretString.getBytes(StandardCharset.UTF_8)); 101 } 102 103 104 /** 105 * Creates a new Message Authentication (MAC) verifier. 106 * 107 * @param secretKey The secret key. Must be at least 256 bits long and 108 * not {@code null}. 109 * 110 * @throws JOSEException If the secret length is shorter than the 111 * minimum 256-bit requirement. 112 */ 113 public MACVerifier(final SecretKey secretKey) 114 throws JOSEException { 115 116 this(secretKey, null); 117 } 118 119 120 /** 121 * Creates a new Message Authentication (MAC) verifier. 122 * 123 * @param jwk The secret as a JWK. Must be at least 256 bits long and 124 * not {@code null}. 125 * 126 * @throws JOSEException If the secret length is shorter than the 127 * minimum 256-bit requirement. 128 */ 129 public MACVerifier(final OctetSequenceKey jwk) 130 throws JOSEException { 131 132 this(jwk.toByteArray()); 133 } 134 135 136 /** 137 * Creates a new Message Authentication (MAC) verifier. 138 * 139 * @param secret The secret. Must be at least 256 bits long 140 * and not {@code null}. 141 * @param defCritHeaders The names of the critical header parameters 142 * that are deferred to the application for 143 * processing, empty set or {@code null} if none. 144 * 145 * @throws JOSEException If the secret length is shorter than the 146 * minimum 256-bit requirement. 147 */ 148 public MACVerifier(final byte[] secret, final Set<String> defCritHeaders) 149 throws JOSEException { 150 151 super(secret); 152 153 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 154 } 155 156 157 /** 158 * Creates a new Message Authentication (MAC) verifier. 159 * 160 * @param secretKey The secret key. Must be at least 256 bits long 161 * and not {@code null}. 162 * @param defCritHeaders The names of the critical header parameters 163 * that are deferred to the application for 164 * processing, empty set or {@code null} if none. 165 * 166 * @throws JOSEException If the secret length is shorter than the 167 * minimum 256-bit requirement. 168 */ 169 public MACVerifier(final SecretKey secretKey, 170 final Set<String> defCritHeaders) 171 throws JOSEException { 172 173 super(secretKey); 174 175 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 176 } 177 178 179 /** 180 * Creates a new Message Authentication (MAC) verifier. 181 * 182 * @param jwk The secret as a JWK. Must be at least 256 bits 183 * long and not {@code null}. 184 * @param defCritHeaders The names of the critical header parameters 185 * that are deferred to the application for 186 * processing, empty set or {@code null} if none. 187 * 188 * @throws JOSEException If the secret length is shorter than the 189 * minimum 256-bit requirement. 190 */ 191 public MACVerifier(final OctetSequenceKey jwk, 192 final Set<String> defCritHeaders) 193 throws JOSEException { 194 195 this(jwk.toByteArray(), defCritHeaders); 196 } 197 198 199 @Override 200 public Set<String> getProcessedCriticalHeaderParams() { 201 202 return critPolicy.getProcessedCriticalHeaderParams(); 203 } 204 205 206 @Override 207 public Set<String> getDeferredCriticalHeaderParams() { 208 209 return critPolicy.getProcessedCriticalHeaderParams(); 210 } 211 212 213 @Override 214 public boolean verify(final JWSHeader header, 215 final byte[] signedContent, 216 final Base64URL signature) 217 throws JOSEException { 218 219 ensureSecretLengthSatisfiesAlgorithm(header.getAlgorithm()); 220 221 if (! critPolicy.headerPasses(header)) { 222 return false; 223 } 224 225 String jcaAlg = getJCAAlgorithmName(header.getAlgorithm()); 226 byte[] expectedHMAC = HMAC.compute(jcaAlg, getSecretKey(), signedContent, getJCAContext().getProvider()); 227 return ConstantTimeUtils.areEqual(expectedHMAC, signature.decode()); 228 } 229}