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, 2008, Oracle and/or its affiliates. All rights reserved.
  25  */
  26 /*
  27  * $Id: DOMDigestMethod.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.dom.DOMCryptoContext;
  33 import javax.xml.crypto.dsig.*;
  34 import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec;
  35 
  36 import java.security.InvalidAlgorithmParameterException;
  37 import java.security.spec.AlgorithmParameterSpec;
  38 import org.w3c.dom.Document;
  39 import org.w3c.dom.Element;
  40 import org.w3c.dom.Node;
  41 
  42 /**
  43  * DOM-based abstract implementation of DigestMethod.
  44  *
  45  * @author Sean Mullan
  46  */
  47 public abstract class DOMDigestMethod extends DOMStructure 
  48     implements DigestMethod {
  49 
  50     static final String SHA384 =
  51         "http://www.w3.org/2001/04/xmldsig-more#sha384"; // see RFC 4051
  52     private DigestMethodParameterSpec params;
  53 
  54     /**
  55      * Creates a <code>DOMDigestMethod</code>.
  56      *
  57      * @param params the algorithm-specific params (may be <code>null</code>)
  58      * @throws InvalidAlgorithmParameterException if the parameters are not
  59      *    appropriate for this digest method
  60      */
  61     DOMDigestMethod(AlgorithmParameterSpec params)
  62         throws InvalidAlgorithmParameterException
  63     {
  64         if (params != null && !(params instanceof DigestMethodParameterSpec)) {
  65             throw new InvalidAlgorithmParameterException
  66                 ("params must be of type DigestMethodParameterSpec");
  67         }
  68         checkParams((DigestMethodParameterSpec)params);
  69         this.params = (DigestMethodParameterSpec)params;
  70     }
  71 
  72     /**
  73      * Creates a <code>DOMDigestMethod</code> from an element. This constructor
  74      * invokes the abstract {@link #unmarshalParams unmarshalParams} method to
  75      * unmarshal any algorithm-specific input parameters.
  76      *
  77      * @param dmElem a DigestMethod element
  78      */
  79     DOMDigestMethod(Element dmElem) throws MarshalException {
  80         Element paramsElem = DOMUtils.getFirstChildElement(dmElem);
  81         if (paramsElem != null) {
  82             params = unmarshalParams(paramsElem);
  83         }
  84         try {
  85             checkParams(params);
  86         } catch (InvalidAlgorithmParameterException iape) {
  87             throw new MarshalException(iape);
  88         }
  89     }
  90 
  91     static DigestMethod unmarshal(Element dmElem) throws MarshalException {
  92         String alg = DOMUtils.getAttributeValue(dmElem, "Algorithm");
  93         if (alg.equals(DigestMethod.SHA1)) {
  94             return new SHA1(dmElem);
  95         } else if (alg.equals(DigestMethod.SHA256)) {
  96             return new SHA256(dmElem);
  97         } else if (alg.equals(SHA384)) {
  98             return new SHA384(dmElem);
  99         } else if (alg.equals(DigestMethod.SHA512)) {
 100             return new SHA512(dmElem);
 101         } else {
 102             throw new MarshalException("unsupported DigestMethod algorithm: " +
 103                                        alg);
 104         }
 105     }
 106 
 107     /**
 108      * Checks if the specified parameters are valid for this algorithm. By
 109      * default, this method throws an exception if parameters are specified
 110      * since most DigestMethod algorithms do not have parameters. Subclasses
 111      * should override it if they have parameters.
 112      *
 113      * @param params the algorithm-specific params (may be <code>null</code>)
 114      * @throws InvalidAlgorithmParameterException if the parameters are not
 115      *    appropriate for this digest method
 116      */
 117     void checkParams(DigestMethodParameterSpec params)
 118         throws InvalidAlgorithmParameterException
 119     {
 120         if (params != null) {
 121             throw new InvalidAlgorithmParameterException("no parameters " +
 122                 "should be specified for the " + getMessageDigestAlgorithm() +
 123                 " DigestMethod algorithm");
 124         }
 125     }
 126 
 127     public final AlgorithmParameterSpec getParameterSpec() {
 128         return params;
 129     }
 130 
 131     /**
 132      * Unmarshals <code>DigestMethodParameterSpec</code> from the specified 
 133      * <code>Element</code>.  By default, this method throws an exception since
 134      * most DigestMethod algorithms do not have parameters. Subclasses should 
 135      * override it if they have parameters.
 136      *
 137      * @param paramsElem the <code>Element</code> holding the input params
 138      * @return the algorithm-specific <code>DigestMethodParameterSpec</code>
 139      * @throws MarshalException if the parameters cannot be unmarshalled
 140      */
 141     DigestMethodParameterSpec unmarshalParams(Element paramsElem)
 142         throws MarshalException
 143     {
 144         throw new MarshalException("no parameters should " +
 145                                    "be specified for the " +
 146                                    getMessageDigestAlgorithm() +
 147                                    " DigestMethod algorithm");
 148     }
 149 
 150     /**
 151      * This method invokes the abstract {@link #marshalParams marshalParams} 
 152      * method to marshal any algorithm-specific parameters.
 153      */
 154     public void marshal(Node parent, String prefix, DOMCryptoContext context)
 155         throws MarshalException
 156     {
 157         Document ownerDoc = DOMUtils.getOwnerDocument(parent);
 158 
 159         Element dmElem = DOMUtils.createElement(ownerDoc, "DigestMethod",
 160                                                 XMLSignature.XMLNS, prefix);
 161         DOMUtils.setAttribute(dmElem, "Algorithm", getAlgorithm());
 162 
 163         if (params != null) {
 164             marshalParams(dmElem, prefix);
 165         }
 166 
 167         parent.appendChild(dmElem);
 168     }
 169 
 170     @Override
 171     public boolean equals(Object o) {
 172         if (this == o) {
 173             return true;
 174         }
 175 
 176         if (!(o instanceof DigestMethod)) {
 177             return false;
 178         }
 179         DigestMethod odm = (DigestMethod)o;
 180 
 181         boolean paramsEqual = (params == null ? odm.getParameterSpec() == null :
 182             params.equals(odm.getParameterSpec()));
 183 
 184         return (getAlgorithm().equals(odm.getAlgorithm()) && paramsEqual);
 185     }
 186     
 187     @Override
 188     public int hashCode() {
 189         int result = 17;
 190         if (params != null) {
 191             result = 31 * result + params.hashCode();
 192         }
 193         result = 31 * result + getAlgorithm().hashCode();
 194         
 195         return result;
 196     }
 197 
 198     /**
 199      * Marshals the algorithm-specific parameters to an Element and
 200      * appends it to the specified parent element. By default, this method
 201      * throws an exception since most DigestMethod algorithms do not have
 202      * parameters. Subclasses should override it if they have parameters.
 203      *
 204      * @param parent the parent element to append the parameters to
 205      * @param the namespace prefix to use
 206      * @throws MarshalException if the parameters cannot be marshalled
 207      */
 208     void marshalParams(Element parent, String prefix)
 209         throws MarshalException
 210     {
 211         throw new MarshalException("no parameters should " +
 212                                    "be specified for the " +
 213                                    getMessageDigestAlgorithm() +
 214                                    " DigestMethod algorithm");
 215     }
 216 
 217     /**
 218      * Returns the MessageDigest standard algorithm name.
 219      */
 220     abstract String getMessageDigestAlgorithm();
 221 
 222     static final class SHA1 extends DOMDigestMethod {
 223         SHA1(AlgorithmParameterSpec params)
 224             throws InvalidAlgorithmParameterException {
 225             super(params);
 226         }
 227         SHA1(Element dmElem) throws MarshalException {
 228             super(dmElem);
 229         }
 230         public String getAlgorithm() {
 231             return DigestMethod.SHA1;
 232         }
 233         String getMessageDigestAlgorithm() {
 234             return "SHA-1";
 235         }
 236     }
 237 
 238     static final class SHA256 extends DOMDigestMethod {
 239         SHA256(AlgorithmParameterSpec params)
 240             throws InvalidAlgorithmParameterException {
 241             super(params);
 242         }
 243         SHA256(Element dmElem) throws MarshalException {
 244             super(dmElem);
 245         }
 246         public String getAlgorithm() {
 247             return DigestMethod.SHA256;
 248         }
 249         String getMessageDigestAlgorithm() {
 250             return "SHA-256";
 251         }
 252     }
 253 
 254     static final class SHA384 extends DOMDigestMethod {
 255         SHA384(AlgorithmParameterSpec params)
 256             throws InvalidAlgorithmParameterException {
 257             super(params);
 258         }
 259         SHA384(Element dmElem) throws MarshalException {
 260             super(dmElem);
 261         }
 262         public String getAlgorithm() {
 263             return SHA384;
 264         }
 265         String getMessageDigestAlgorithm() {
 266             return "SHA-384";
 267         }
 268     }
 269 
 270     static final class SHA512 extends DOMDigestMethod {
 271         SHA512(AlgorithmParameterSpec params)
 272             throws InvalidAlgorithmParameterException {
 273             super(params);
 274         }
 275         SHA512(Element dmElem) throws MarshalException {
 276             super(dmElem);
 277         }
 278         public String getAlgorithm() {
 279             return DigestMethod.SHA512;
 280         }
 281         String getMessageDigestAlgorithm() {
 282             return "SHA-512";
 283         }
 284     }
 285 }