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
24package org.jcp.xml.dsig.internal.dom;
25
26import java.security.Key;
27import java.security.InvalidAlgorithmParameterException;
28import java.security.InvalidKeyException;
29import java.security.SignatureException;
30import java.security.spec.AlgorithmParameterSpec;
31import javax.xml.crypto.MarshalException;
32import javax.xml.crypto.dom.DOMCryptoContext;
33import javax.xml.crypto.dsig.SignatureMethod;
34import javax.xml.crypto.dsig.SignedInfo;
35import javax.xml.crypto.dsig.XMLSignature;
36import javax.xml.crypto.dsig.XMLSignatureException;
37import javax.xml.crypto.dsig.XMLSignContext;
38import javax.xml.crypto.dsig.XMLValidateContext;
39import javax.xml.crypto.dsig.spec.SignatureMethodParameterSpec;
40import org.w3c.dom.Document;
41import org.w3c.dom.Element;
42import org.w3c.dom.Node;
43
44/**
45 * An abstract class representing a SignatureMethod. Subclasses implement
46 * a specific XML DSig signature algorithm.
47 */
48abstract class AbstractDOMSignatureMethod extends DOMStructure
49    implements SignatureMethod {
50
51    // denotes the type of signature algorithm
52    enum Type { DSA, RSA, ECDSA, HMAC }
53
54    /**
55     * Verifies the passed-in signature with the specified key, using the
56     * underlying Signature or Mac algorithm.
57     *
58     * @param key the verification key
59     * @param si the SignedInfo
60     * @param sig the signature bytes to be verified
61     * @param context the XMLValidateContext
62     * @return <code>true</code> if the signature verified successfully,
63     *    <code>false</code> if not
64     * @throws NullPointerException if <code>key</code>, <code>si</code> or
65     *    <code>sig</code> are <code>null</code>
66     * @throws InvalidKeyException if the key is improperly encoded, of
67     *    the wrong type, or parameters are missing, etc
68     * @throws SignatureException if an unexpected error occurs, such
69     *    as the passed in signature is improperly encoded
70     * @throws XMLSignatureException if an unexpected error occurs
71     */
72    abstract boolean verify(Key key, SignedInfo si, byte[] sig,
73                            XMLValidateContext context)
74        throws InvalidKeyException, SignatureException, XMLSignatureException;
75
76    /**
77     * Signs the bytes with the specified key, using the underlying
78     * Signature or Mac algorithm.
79     *
80     * @param key the signing key
81     * @param si the SignedInfo
82     * @param context the XMLSignContext
83     * @return the signature
84     * @throws NullPointerException if <code>key</code> or
85     *    <code>si</code> are <code>null</code>
86     * @throws InvalidKeyException if the key is improperly encoded, of
87     *    the wrong type, or parameters are missing, etc
88     * @throws XMLSignatureException if an unexpected error occurs
89     */
90    abstract byte[] sign(Key key, SignedInfo si, XMLSignContext context)
91        throws InvalidKeyException, XMLSignatureException;
92
93    /**
94     * Returns the java.security.Signature or javax.crypto.Mac standard
95     * algorithm name.
96     */
97    abstract String getJCAAlgorithm();
98
99    /**
100     * Returns the type of signature algorithm.
101     */
102    abstract Type getAlgorithmType();
103
104    /**
105     * This method invokes the {@link #marshalParams marshalParams}
106     * method to marshal any algorithm-specific parameters.
107     */
108    public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
109        throws MarshalException
110    {
111        Document ownerDoc = DOMUtils.getOwnerDocument(parent);
112
113        Element smElem = DOMUtils.createElement(ownerDoc, "SignatureMethod",
114                                                XMLSignature.XMLNS, dsPrefix);
115        DOMUtils.setAttribute(smElem, "Algorithm", getAlgorithm());
116
117        if (getParameterSpec() != null) {
118            marshalParams(smElem, dsPrefix);
119        }
120
121        parent.appendChild(smElem);
122    }
123
124    /**
125     * Marshals the algorithm-specific parameters to an Element and
126     * appends it to the specified parent element. By default, this method
127     * throws an exception since most SignatureMethod algorithms do not have
128     * parameters. Subclasses should override it if they have parameters.
129     *
130     * @param parent the parent element to append the parameters to
131     * @param paramsPrefix the algorithm parameters prefix to use
132     * @throws MarshalException if the parameters cannot be marshalled
133     */
134    void marshalParams(Element parent, String paramsPrefix)
135        throws MarshalException
136    {
137        throw new MarshalException("no parameters should " +
138                                   "be specified for the " + getAlgorithm() +
139                                   " SignatureMethod algorithm");
140    }
141
142    /**
143     * Unmarshals <code>SignatureMethodParameterSpec</code> from the specified
144     * <code>Element</code>. By default, this method throws an exception since
145     * most SignatureMethod algorithms do not have parameters. Subclasses should
146     * override it if they have parameters.
147     *
148     * @param paramsElem the <code>Element</code> holding the input params
149     * @return the algorithm-specific <code>SignatureMethodParameterSpec</code>
150     * @throws MarshalException if the parameters cannot be unmarshalled
151     */
152    SignatureMethodParameterSpec unmarshalParams(Element paramsElem)
153        throws MarshalException
154    {
155        throw new MarshalException("no parameters should " +
156                                   "be specified for the " + getAlgorithm() +
157                                   " SignatureMethod algorithm");
158    }
159
160    /**
161     * Checks if the specified parameters are valid for this algorithm. By
162     * default, this method throws an exception if parameters are specified
163     * since most SignatureMethod algorithms do not have parameters. Subclasses
164     * should override it if they have parameters.
165     *
166     * @param params the algorithm-specific params (may be <code>null</code>)
167     * @throws InvalidAlgorithmParameterException if the parameters are not
168     *    appropriate for this signature method
169     */
170    void checkParams(SignatureMethodParameterSpec params)
171        throws InvalidAlgorithmParameterException
172    {
173        if (params != null) {
174            throw new InvalidAlgorithmParameterException("no parameters " +
175                "should be specified for the " + getAlgorithm() +
176                " SignatureMethod algorithm");
177        }
178    }
179
180    @Override
181    public boolean equals(Object o)
182    {
183        if (this == o) {
184            return true;
185        }
186
187        if (!(o instanceof SignatureMethod)) {
188            return false;
189        }
190        SignatureMethod osm = (SignatureMethod)o;
191
192        return (getAlgorithm().equals(osm.getAlgorithm()) &&
193            paramsEqual(osm.getParameterSpec()));
194    }
195
196    @Override
197    public int hashCode() {
198        int result = 17;
199        result = 31 * result + getAlgorithm().hashCode();
200        AlgorithmParameterSpec spec = getParameterSpec();
201        if (spec != null) {
202            result = 31 * result + spec.hashCode();
203        }
204
205        return result;
206    }
207
208    /**
209     * Returns true if parameters are equal; false otherwise.
210     *
211     * Subclasses should override this method to compare algorithm-specific
212     * parameters.
213     */
214    boolean paramsEqual(AlgorithmParameterSpec spec)
215    {
216        return (getParameterSpec() == spec);
217    }
218}
219