1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /** 6 * Licensed to the Apache Software Foundation (ASF) under one 7 * or more contributor license agreements. See the NOTICE file 8 * distributed with this work for additional information 9 * regarding copyright ownership. The ASF licenses this file 10 * to you under the Apache License, Version 2.0 (the 11 * "License"); you may not use this file except in compliance 12 * with the License. You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, 17 * software distributed under the License is distributed on an 18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 * KIND, either express or implied. See the License for the 20 * specific language governing permissions and limitations 21 * under the License. 22 */ 23 /* 24 * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. 25 */ 26 /* 27 * $Id: DOMHMACSignatureMethod.java 1333415 2012-05-03 12:03:51Z coheigea $ 28 */ 29 package org.jcp.xml.dsig.internal.dom; 30 31 import javax.xml.crypto.*; 32 import javax.xml.crypto.dsig.*; 33 import javax.xml.crypto.dsig.spec.HMACParameterSpec; 34 import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec; 35 36 import java.security.InvalidAlgorithmParameterException; 37 import java.security.InvalidKeyException; 38 import java.security.Key; 39 import java.security.MessageDigest; 40 import java.security.NoSuchAlgorithmException; 41 import java.security.SignatureException; 42 import java.security.spec.AlgorithmParameterSpec; 43 import javax.crypto.Mac; 44 import javax.crypto.SecretKey; 45 import org.w3c.dom.Document; 46 import org.w3c.dom.Element; 47 48 import org.jcp.xml.dsig.internal.MacOutputStream; 49 50 /** 51 * DOM-based implementation of HMAC SignatureMethod. 52 * 53 * @author Sean Mullan 54 */ 55 public abstract class DOMHMACSignatureMethod extends AbstractDOMSignatureMethod { 56 57 private static java.util.logging.Logger log = 58 java.util.logging.Logger.getLogger("org.jcp.xml.dsig.internal.dom"); 59 60 // see RFC 4051 for these algorithm definitions 61 static final String HMAC_SHA256 = 62 "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; 63 static final String HMAC_SHA384 = 64 "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384"; 65 static final String HMAC_SHA512 = 66 "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"; 67 68 private Mac hmac; 69 private int outputLength; 70 private boolean outputLengthSet; 71 private SignatureMethodParameterSpec params; 72 73 /** 74 * Creates a <code>DOMHMACSignatureMethod</code> with the specified params 75 * 76 * @param params algorithm-specific parameters (may be <code>null</code>) 77 * @throws InvalidAlgorithmParameterException if params are inappropriate 78 */ 79 DOMHMACSignatureMethod(AlgorithmParameterSpec params) 80 throws InvalidAlgorithmParameterException 81 { 82 checkParams((SignatureMethodParameterSpec)params); 83 this.params = (SignatureMethodParameterSpec)params; 84 } 85 86 /** 87 * Creates a <code>DOMHMACSignatureMethod</code> from an element. 88 * 89 * @param smElem a SignatureMethod element 90 */ 91 DOMHMACSignatureMethod(Element smElem) throws MarshalException { 92 Element paramsElem = DOMUtils.getFirstChildElement(smElem); 93 if (paramsElem != null) { 94 params = unmarshalParams(paramsElem); 95 } 96 try { 97 checkParams(params); 98 } catch (InvalidAlgorithmParameterException iape) { 99 throw new MarshalException(iape); 100 } 101 } 102 103 void checkParams(SignatureMethodParameterSpec params) 104 throws InvalidAlgorithmParameterException 105 { 106 if (params != null) { 107 if (!(params instanceof HMACParameterSpec)) { 108 throw new InvalidAlgorithmParameterException 109 ("params must be of type HMACParameterSpec"); 110 } 111 outputLength = ((HMACParameterSpec)params).getOutputLength(); 112 outputLengthSet = true; 113 if (log.isLoggable(java.util.logging.Level.FINE)) { 114 log.log(java.util.logging.Level.FINE, "Setting outputLength from HMACParameterSpec to: " + outputLength); 115 } 116 } 117 } 118 119 public final AlgorithmParameterSpec getParameterSpec() { 120 return params; 121 } 122 123 SignatureMethodParameterSpec unmarshalParams(Element paramsElem) 124 throws MarshalException 125 { 126 outputLength = Integer.valueOf(paramsElem.getFirstChild().getNodeValue()).intValue(); 127 outputLengthSet = true; 128 if (log.isLoggable(java.util.logging.Level.FINE)) { 129 log.log(java.util.logging.Level.FINE, "unmarshalled outputLength: " + outputLength); 130 } 131 return new HMACParameterSpec(outputLength); 132 } 133 134 void marshalParams(Element parent, String prefix) 135 throws MarshalException 136 { 137 Document ownerDoc = DOMUtils.getOwnerDocument(parent); 138 Element hmacElem = DOMUtils.createElement(ownerDoc, "HMACOutputLength", 139 XMLSignature.XMLNS, prefix); 140 hmacElem.appendChild(ownerDoc.createTextNode 141 (String.valueOf(outputLength))); 142 143 parent.appendChild(hmacElem); 144 } 145 146 boolean verify(Key key, SignedInfo si, byte[] sig, 147 XMLValidateContext context) 148 throws InvalidKeyException, SignatureException, XMLSignatureException 149 { 150 if (key == null || si == null || sig == null) { 151 throw new NullPointerException(); 152 } 153 if (!(key instanceof SecretKey)) { 154 throw new InvalidKeyException("key must be SecretKey"); 155 } 156 if (hmac == null) { 157 try { 158 hmac = Mac.getInstance(getJCAAlgorithm()); 159 } catch (NoSuchAlgorithmException nsae) { 160 throw new XMLSignatureException(nsae); 161 } 162 } 163 if (outputLengthSet && outputLength < getDigestLength()) { 164 throw new XMLSignatureException 165 ("HMACOutputLength must not be less than " + getDigestLength()); 166 } 167 hmac.init((SecretKey)key); 168 ((DOMSignedInfo)si).canonicalize(context, new MacOutputStream(hmac)); 169 byte[] result = hmac.doFinal(); 170 171 return MessageDigest.isEqual(sig, result); 172 } 173 174 byte[] sign(Key key, SignedInfo si, XMLSignContext context) 175 throws InvalidKeyException, XMLSignatureException 176 { 177 if (key == null || si == null) { 178 throw new NullPointerException(); 179 } 180 if (!(key instanceof SecretKey)) { 181 throw new InvalidKeyException("key must be SecretKey"); 182 } 183 if (hmac == null) { 184 try { 185 hmac = Mac.getInstance(getJCAAlgorithm()); 186 } catch (NoSuchAlgorithmException nsae) { 187 throw new XMLSignatureException(nsae); 188 } 189 } 190 if (outputLengthSet && outputLength < getDigestLength()) { 191 throw new XMLSignatureException 192 ("HMACOutputLength must not be less than " + getDigestLength()); 193 } 194 hmac.init((SecretKey)key); 195 ((DOMSignedInfo)si).canonicalize(context, new MacOutputStream(hmac)); 196 return hmac.doFinal(); 197 } 198 199 boolean paramsEqual(AlgorithmParameterSpec spec) { 200 if (getParameterSpec() == spec) { 201 return true; 202 } 203 if (!(spec instanceof HMACParameterSpec)) { 204 return false; 205 } 206 HMACParameterSpec ospec = (HMACParameterSpec)spec; 207 208 return (outputLength == ospec.getOutputLength()); 209 } 210 211 Type getAlgorithmType() { 212 return Type.HMAC; 213 } 214 215 /** 216 * Returns the output length of the hash/digest. 217 */ 218 abstract int getDigestLength(); 219 220 static final class SHA1 extends DOMHMACSignatureMethod { 221 SHA1(AlgorithmParameterSpec params) 222 throws InvalidAlgorithmParameterException { 223 super(params); 224 } 225 SHA1(Element dmElem) throws MarshalException { 226 super(dmElem); 227 } 228 public String getAlgorithm() { 229 return SignatureMethod.HMAC_SHA1; 230 } 231 String getJCAAlgorithm() { 232 return "HmacSHA1"; 233 } 234 int getDigestLength() { 235 return 160; 236 } 237 } 238 239 static final class SHA256 extends DOMHMACSignatureMethod { 240 SHA256(AlgorithmParameterSpec params) 241 throws InvalidAlgorithmParameterException { 242 super(params); 243 } 244 SHA256(Element dmElem) throws MarshalException { 245 super(dmElem); 246 } 247 public String getAlgorithm() { 248 return HMAC_SHA256; 249 } 250 String getJCAAlgorithm() { 251 return "HmacSHA256"; 252 } 253 int getDigestLength() { 254 return 256; 255 } 256 } 257 258 static final class SHA384 extends DOMHMACSignatureMethod { 259 SHA384(AlgorithmParameterSpec params) 260 throws InvalidAlgorithmParameterException { 261 super(params); 262 } 263 SHA384(Element dmElem) throws MarshalException { 264 super(dmElem); 265 } 266 public String getAlgorithm() { 267 return HMAC_SHA384; 268 } 269 String getJCAAlgorithm() { 270 return "HmacSHA384"; 271 } 272 int getDigestLength() { 273 return 384; 274 } 275 } 276 277 static final class SHA512 extends DOMHMACSignatureMethod { 278 SHA512(AlgorithmParameterSpec params) 279 throws InvalidAlgorithmParameterException { 280 super(params); 281 } 282 SHA512(Element dmElem) throws MarshalException { 283 super(dmElem); 284 } 285 public String getAlgorithm() { 286 return HMAC_SHA512; 287 } 288 String getJCAAlgorithm() { 289 return "HmacSHA512"; 290 } 291 int getDigestLength() { 292 return 512; 293 } 294 } 295 }