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 }