1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2005 The Apache Software Foundation.
   7  *
   8  *  Licensed under the Apache License, Version 2.0 (the "License");
   9  *  you may not use this file except in compliance with the License.
  10  *  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  *  Unless required by applicable law or agreed to in writing, software
  15  *  distributed under the License is distributed on an "AS IS" BASIS,
  16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  *  See the License for the specific language governing permissions and
  18  *  limitations under the License.
  19  *
  20  */
  21 /*
  22  * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 /*
  25  * $Id: DOMDigestMethod.java,v 1.2 2008/07/24 15:20:32 mullan Exp $
  26  */
  27 package org.jcp.xml.dsig.internal.dom;
  28 
  29 import javax.xml.crypto.*;
  30 import javax.xml.crypto.dom.DOMCryptoContext;
  31 import javax.xml.crypto.dsig.*;
  32 import javax.xml.crypto.dsig.spec.DigestMethodParameterSpec;
  33 
  34 import java.security.InvalidAlgorithmParameterException;
  35 import java.security.spec.AlgorithmParameterSpec;
  36 import org.w3c.dom.Document;
  37 import org.w3c.dom.Element;
  38 import org.w3c.dom.Node;
  39 
  40 /**
  41  * DOM-based abstract implementation of DigestMethod.
  42  *
  43  * @author Sean Mullan
  44  */
  45 public abstract class DOMDigestMethod extends DOMStructure
  46     implements DigestMethod {
  47 
  48     final static String SHA384 =
  49         "http://www.w3.org/2001/04/xmldsig-more#sha384"; // see RFC 4051
  50     private DigestMethodParameterSpec params;
  51 
  52     /**
  53      * Creates a <code>DOMDigestMethod</code>.
  54      *
  55      * @param params the algorithm-specific params (may be <code>null</code>)
  56      * @throws InvalidAlgorithmParameterException if the parameters are not
  57      *    appropriate for this digest method
  58      */
  59     DOMDigestMethod(AlgorithmParameterSpec params)
  60         throws InvalidAlgorithmParameterException {
  61         if (params != null && !(params instanceof DigestMethodParameterSpec)) {
  62             throw new InvalidAlgorithmParameterException
  63                 ("params must be of type DigestMethodParameterSpec");
  64         }
  65         checkParams((DigestMethodParameterSpec) params);
  66         this.params = (DigestMethodParameterSpec) params;
  67     }
  68 
  69     /**
  70      * Creates a <code>DOMDigestMethod</code> from an element. This constructor
  71      * invokes the abstract {@link #unmarshalParams unmarshalParams} method to
  72      * unmarshal any algorithm-specific input parameters.
  73      *
  74      * @param dmElem a DigestMethod element
  75      */
  76     DOMDigestMethod(Element dmElem) throws MarshalException {
  77         Element paramsElem = DOMUtils.getFirstChildElement(dmElem);
  78         if (paramsElem != null) {
  79             params = unmarshalParams(paramsElem);
  80         }
  81         try {
  82             checkParams(params);
  83         } catch (InvalidAlgorithmParameterException iape) {
  84             throw new MarshalException(iape);
  85         }
  86     }
  87 
  88     static DigestMethod unmarshal(Element dmElem) throws MarshalException {
  89         String alg = DOMUtils.getAttributeValue(dmElem, "Algorithm");
  90         if (alg.equals(DigestMethod.SHA1)) {
  91             return new SHA1(dmElem);
  92         } else if (alg.equals(DigestMethod.SHA256)) {
  93             return new SHA256(dmElem);
  94         } else if (alg.equals(SHA384)) {
  95             return new SHA384(dmElem);
  96         } else if (alg.equals(DigestMethod.SHA512)) {
  97             return new SHA512(dmElem);
  98         } else {
  99             throw new MarshalException
 100                 ("unsupported DigestMethod algorithm: " + alg);
 101         }
 102     }
 103 
 104     /**
 105      * Checks if the specified parameters are valid for this algorithm. By
 106      * default, this method throws an exception if parameters are specified
 107      * since most DigestMethod algorithms do not have parameters. Subclasses
 108      * should override it if they have parameters.
 109      *
 110      * @param params the algorithm-specific params (may be <code>null</code>)
 111      * @throws InvalidAlgorithmParameterException if the parameters are not
 112      *    appropriate for this digest method
 113      */
 114     void checkParams(DigestMethodParameterSpec params)
 115         throws InvalidAlgorithmParameterException {
 116         if (params != null) {
 117             throw new InvalidAlgorithmParameterException("no parameters " +
 118                 "should be specified for the " + getMessageDigestAlgorithm()
 119                  + " DigestMethod algorithm");
 120         }
 121     }
 122 
 123     public final AlgorithmParameterSpec getParameterSpec() {
 124         return params;
 125     }
 126 
 127     /**
 128      * Unmarshals <code>DigestMethodParameterSpec</code> from the specified
 129      * <code>Element</code>.  By default, this method throws an exception since
 130      * most DigestMethod algorithms do not have parameters. Subclasses should
 131      * override it if they have parameters.
 132      *
 133      * @param paramsElem the <code>Element</code> holding the input params
 134      * @return the algorithm-specific <code>DigestMethodParameterSpec</code>
 135      * @throws MarshalException if the parameters cannot be unmarshalled
 136      */
 137     DigestMethodParameterSpec
 138         unmarshalParams(Element paramsElem) throws MarshalException {
 139         throw new MarshalException("no parameters should " +
 140             "be specified for the " + getMessageDigestAlgorithm() +
 141             " DigestMethod algorithm");
 142     }
 143 
 144     /**
 145      * This method invokes the abstract {@link #marshalParams marshalParams}
 146      * method to marshal any algorithm-specific parameters.
 147      */
 148     public void marshal(Node parent, String prefix, DOMCryptoContext context)
 149         throws MarshalException {
 150         Document ownerDoc = DOMUtils.getOwnerDocument(parent);
 151 
 152         Element dmElem = DOMUtils.createElement
 153             (ownerDoc, "DigestMethod", XMLSignature.XMLNS, prefix);
 154         DOMUtils.setAttribute(dmElem, "Algorithm", getAlgorithm());
 155 
 156         if (params != null) {
 157             marshalParams(dmElem, prefix);
 158         }
 159 
 160         parent.appendChild(dmElem);
 161     }
 162 
 163     public boolean equals(Object o) {
 164         if (this == o) {
 165             return true;
 166         }
 167 
 168         if (!(o instanceof DigestMethod)) {
 169             return false;
 170         }
 171         DigestMethod odm = (DigestMethod) o;
 172 
 173         boolean paramsEqual = (params == null ? odm.getParameterSpec() == null :
 174             params.equals(odm.getParameterSpec()));
 175 
 176         return (getAlgorithm().equals(odm.getAlgorithm()) && paramsEqual);
 177     }
 178 
 179     /**
 180      * Marshals the algorithm-specific parameters to an Element and
 181      * appends it to the specified parent element. By default, this method
 182      * throws an exception since most DigestMethod algorithms do not have
 183      * parameters. Subclasses should override it if they have parameters.
 184      *
 185      * @param parent the parent element to append the parameters to
 186      * @param the namespace prefix to use
 187      * @throws MarshalException if the parameters cannot be marshalled
 188      */
 189     void marshalParams(Element parent, String prefix)
 190         throws MarshalException {
 191         throw new MarshalException("no parameters should " +
 192             "be specified for the " + getMessageDigestAlgorithm() +
 193             " DigestMethod algorithm");
 194     }
 195 
 196     /**
 197      * Returns the MessageDigest standard algorithm name.
 198      */
 199     abstract String getMessageDigestAlgorithm();
 200 
 201     static final class SHA1 extends DOMDigestMethod {
 202         SHA1(AlgorithmParameterSpec params)
 203             throws InvalidAlgorithmParameterException {
 204             super(params);
 205         }
 206         SHA1(Element dmElem) throws MarshalException {
 207             super(dmElem);
 208         }
 209         public String getAlgorithm() {
 210             return DigestMethod.SHA1;
 211         }
 212         String getMessageDigestAlgorithm() {
 213             return "SHA-1";
 214         }
 215     }
 216 
 217     static final class SHA256 extends DOMDigestMethod {
 218         SHA256(AlgorithmParameterSpec params)
 219             throws InvalidAlgorithmParameterException {
 220             super(params);
 221         }
 222         SHA256(Element dmElem) throws MarshalException {
 223             super(dmElem);
 224         }
 225         public String getAlgorithm() {
 226             return DigestMethod.SHA256;
 227         }
 228         String getMessageDigestAlgorithm() {
 229             return "SHA-256";
 230         }
 231     }
 232 
 233     static final class SHA384 extends DOMDigestMethod {
 234         SHA384(AlgorithmParameterSpec params)
 235             throws InvalidAlgorithmParameterException {
 236             super(params);
 237         }
 238         SHA384(Element dmElem) throws MarshalException {
 239             super(dmElem);
 240         }
 241         public String getAlgorithm() {
 242             return SHA384;
 243         }
 244         String getMessageDigestAlgorithm() {
 245             return "SHA-384";
 246         }
 247     }
 248 
 249     static final class SHA512 extends DOMDigestMethod {
 250         SHA512(AlgorithmParameterSpec params)
 251             throws InvalidAlgorithmParameterException {
 252             super(params);
 253         }
 254         SHA512(Element dmElem) throws MarshalException {
 255             super(dmElem);
 256         }
 257         public String getAlgorithm() {
 258             return DigestMethod.SHA512;
 259         }
 260         String getMessageDigestAlgorithm() {
 261             return "SHA-512";
 262         }
 263     }
 264 }