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.StandardCharset; 032import net.jcip.annotations.ThreadSafe; 033 034import javax.crypto.SecretKey; 035import java.util.Set; 036 037 038/** 039 * Message Authentication Code (MAC) verifier of 040 * {@link com.nimbusds.jose.JWSObject JWS objects}. Expects a secret key. 041 * 042 * <p>See RFC 7518 043 * <a href="https://tools.ietf.org/html/rfc7518#section-3.2">section 3.2</a> 044 * for more information. 045 * 046 * <p>This class is thread-safe. 047 * 048 * <p>Supports the following algorithms: 049 * 050 * <ul> 051 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS256} 052 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS384} 053 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS512} 054 * </ul> 055 * 056 <p>Tested with the AWS CloudHSM JCE provider. 057 * 058 * @author Vladimir Dzhuvinov 059 * @version 2016-06-26 060 */ 061@ThreadSafe 062public class MACVerifier extends MACProvider implements JWSVerifier, CriticalHeaderParamsAware { 063 064 065 /** 066 * The critical header policy. 067 */ 068 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 069 070 071 /** 072 * Creates a new Message Authentication (MAC) verifier. 073 * 074 * @param secret The secret. Must be at least 256 bits long and not 075 * {@code null}. 076 * 077 * @throws JOSEException If the secret length is shorter than the 078 * minimum 256-bit requirement. 079 */ 080 public MACVerifier(final byte[] secret) 081 throws JOSEException { 082 083 this(secret, null); 084 } 085 086 087 /** 088 * Creates a new Message Authentication (MAC) verifier. 089 * 090 * @param secretString The secret as a UTF-8 encoded string. Must be at 091 * least 256 bits long and not {@code null}. 092 * 093 * @throws JOSEException If the secret length is shorter than the 094 * minimum 256-bit requirement. 095 */ 096 public MACVerifier(final String secretString) 097 throws JOSEException { 098 099 this(secretString.getBytes(StandardCharset.UTF_8)); 100 } 101 102 103 /** 104 * Creates a new Message Authentication (MAC) verifier. 105 * 106 * @param secretKey The secret key. Must be at least 256 bits long and 107 * not {@code null}. 108 * 109 * @throws JOSEException If the secret length is shorter than the 110 * minimum 256-bit requirement. 111 */ 112 public MACVerifier(final SecretKey secretKey) 113 throws JOSEException { 114 115 this(secretKey, null); 116 } 117 118 119 /** 120 * Creates a new Message Authentication (MAC) verifier. 121 * 122 * @param jwk The secret as a JWK. Must be at least 256 bits long and 123 * not {@code null}. 124 * 125 * @throws JOSEException If the secret length is shorter than the 126 * minimum 256-bit requirement. 127 */ 128 public MACVerifier(final OctetSequenceKey jwk) 129 throws JOSEException { 130 131 this(jwk.toByteArray()); 132 } 133 134 135 /** 136 * Creates a new Message Authentication (MAC) verifier. 137 * 138 * @param secret The secret. Must be at least 256 bits long 139 * and not {@code null}. 140 * @param defCritHeaders The names of the critical header parameters 141 * that are deferred to the application for 142 * processing, empty set or {@code null} if none. 143 * 144 * @throws JOSEException If the secret length is shorter than the 145 * minimum 256-bit requirement. 146 */ 147 public MACVerifier(final byte[] secret, 148 final Set<String> defCritHeaders) 149 throws JOSEException { 150 151 super(secret, SUPPORTED_ALGORITHMS); 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, SUPPORTED_ALGORITHMS); 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 if (! critPolicy.headerPasses(header)) { 220 return false; 221 } 222 223 String jcaAlg = getJCAAlgorithmName(header.getAlgorithm()); 224 byte[] expectedHMAC = HMAC.compute(jcaAlg, getSecretKey(), signedContent, getJCAContext().getProvider()); 225 return ConstantTimeUtils.areEqual(expectedHMAC, signature.decode()); 226 } 227}