1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /*
21  * XSEC
22  *
23  * DSIG_Reference := Class for checking and setting up reference nodes in a DSIG signature
24  *
25  * $Id: DSIGReference.hpp 1894269 2021-10-14 20:25:32Z scantor $
26  *
27  */
28 
29 #ifndef DSIGREFERENCE_INCLUDE
30 #define DSIGREFERENCE_INCLUDE
31 
32 // High level include
33 #include <xsec/framework/XSECDefs.hpp>
34 
35 // Xerces INcludes
36 
37 #include <xercesc/dom/DOM.hpp>
38 #include <xercesc/dom/DOMNamedNodeMap.hpp>
39 
40 // XSEC Includes
41 #include <xsec/utils/XSECSafeBufferFormatter.hpp>
42 #include <xsec/dsig/DSIGTransform.hpp>
43 #include <xsec/dsig/DSIGReferenceList.hpp>
44 #include <xsec/dsig/DSIGConstants.hpp>
45 
46 class DSIGTransformList;
47 class DSIGTransformBase64;
48 class DSIGTransformC14n;
49 class DSIGTransformEnvelope;
50 class DSIGTransformXPath;
51 class DSIGTransformXPathFilter;
52 class DSIGTransformXSL;
53 class DSIGSignature;
54 class DSIGSignedInfo;
55 
56 class TXFMBase;
57 class TXFMChain;
58 class XSECBinTXFMInputStream;
59 class XSECURIResolver;
60 class XSECEnv;
61 
62 /**
63  * @ingroup pubsig
64  */
65 
66 /**
67  * @brief The class used for manipulating Reference Elements within a signature.
68  *
69  * <p>The DSIGReference class creates and manipulates (including hashing and validating)
70  * \<Reference\> elements.</p>
71  *
72  */
73 
74 class XSEC_EXPORT DSIGReference {
75 
76 public:
77 
78     /** @name Constructors and Destructors */
79     //@{
80 
81     /**
82 	 * \brief Contructor for use with existing XML signatures or templates.
83 	 *
84 	 * <p>Create a DSIGReference object based on an already existing
85 	 * DSIG Reference XML node.  It is assumed that the underlying
86 	 * DOM structure is in place and works correctly.</p>
87 	 *
88 	 * @note DSIGReference structures should only ever be created via calls to a
89 	 * DSIGSignature object.
90 	 *
91 	 * @param env The operating environment in which the Reference is operating
92 	 * @param dom The DOM node (within doc) that is to be used as the base of the reference.
93 	 * @see #load
94 	 * @see DSIGSignature#createReference
95 	 */
96 
97 	DSIGReference(const XSECEnv * env, XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *dom);
98 
99     /**
100 	 * \brief Contructor for use when creating new Reference structures.
101 	 *
102 	 * <p>Create a DSIGReference object that can later be used to create
103 	 * a new Reference structure in the DOM document.</p>
104 	 *
105 	 * @note DSIGReference structures should only ever be created via calls to a
106 	 * DSIGSignature object.
107 	 *
108 	 * @param env The environment object for this reference.
109 	 * @see #load
110 	 * @see DSIGSignature#createReference
111 	 */
112 
113 	DSIGReference(const XSECEnv * env);
114 
115 	/**
116 	 * \brief Destructor.
117 	 *
118 	 * @note Does not impact any created DOM structures when destroyed.
119 	 *
120 	 * @note DSIGReferences should <em>never</em> be destroyed/deleted by
121 	 * applications.  They are owned and managed by DSIGSignature structures.
122 	 */
123 
124 	~DSIGReference();
125 
126 	//@}
127 
128     /** @name Reference Construction and Manipulation */
129     //@{
130 
131 	/**
132 	 * \brief Load a DSIGReference from an existing DOM structure.
133 	 *
134 	 * <p>This function will load a Reference structure from the owner
135 	 * document.</p>
136 	 *
137 	 */
138 
139 	void load();
140 
141 	/**
142 	 * \brief Create a Reference structure in the document.
143 	 *
144 	 * <p>This function will create a Reference structure in the owner
145 	 * document.  In some cases, a call to this function will be sufficient
146 	 * to put the required Reference in place.  In other cases, calls will
147 	 * also need to be made to the various append*Transform methods.</p>
148 	 *
149 	 * @note The XSEC Library currently makes very little use of <em>type</em>
150 	 * attributes in \<Reference\> Elements.  However this may of use to calling
151 	 * applications.
152 	 *
153 	 * @param URI The URI (data source) for this reference.  Set to NULL for
154 	 * an anonymous reference.
155 	 * @param hashAlgorithmURI The type of Digest to be used (generally SHA-1)
156 	 * @param type A type string (as defined by XML Signature).
157 	 * @returns The root Reference element of the newly created DOM structure.
158 	 */
159 
160 	XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *
161 		createBlankReference(const XMLCh * URI,
162 			const XMLCh * hashAlgorithmURI,
163 			const XMLCh * type);
164 
165 	/**
166 	 * \brief Append an Enveloped Signature Transform to the Reference.
167 	 *
168 	 * Appends a simple enveloped-signature transform to the list of transforms
169 	 * in this element.
170 	 *
171 	 * @returns The newly created envelope transform.
172 	 *
173 	 */
174 
175 	DSIGTransformEnvelope *  appendEnvelopedSignatureTransform();
176 
177 	/**
178 	 * \brief Append a Base64 Transform to the Reference.
179 	 *
180 	 * @returns The newly created Base64 transform.
181 	 */
182 
183 	DSIGTransformBase64 * appendBase64Transform();
184 
185 	/**
186 	 * \brief Append an XPath Transform to the Reference.
187 	 *
188 	 * <p> Append an XPath transform.  Namespaces can be added to the
189 	 * transform directly using the returned <em>DSIGTransformXPath</em>
190 	 * structure</p>
191 	 *
192 	 * @param expr The XPath expression to be placed in the transform.
193 	 * @returns The newly created XPath transform
194 	 */
195 
196 	DSIGTransformXPath * appendXPathTransform(const char * expr);
197 
198 	/**
199 	 * \brief Append an XPath-Filter2 Transform to the Reference.
200 	 *
201 	 * The returned DSIGTransformXPathFilter will have no actual filter
202 	 * expressions loaded, but calls can be made to
203 	 * DSIGTransformXPathFilter::appendTransform to add them.
204 	 *
205 	 * @returns The newly created XPath Filter transform
206 	 */
207 
208 	DSIGTransformXPathFilter * appendXPathFilterTransform(void);
209 
210 	/**
211 	 * \brief Append an XSLT Transform to the Reference.
212 	 *
213 	 * <p>The caller must have already create the stylesheet and turned it into
214 	 * a DOM structure that is passed in as the stylesheet parameter.</p>
215 	 *
216 	 * @param stylesheet The stylesheet DOM structure to be placed in the reference.
217 	 * @returns The newly create XSLT transform
218 	 */
219 
220 	DSIGTransformXSL * appendXSLTransform(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *stylesheet);
221 
222 	/**
223 	 * \brief Append a Canonicalization Transform to the Reference.
224 	 *
225 	 * @param canonicalizationAlgorithmURI The type of canonicalisation to be added.
226 	 * @returns The newly create canonicalisation transform
227 	 */
228 
229 	DSIGTransformC14n * appendCanonicalizationTransform(
230 		const XMLCh * canonicalizationAlgorithmURI
231 	);
232 
233 	/**
234 	 * \brief Append a "debug" transformer.
235 	 *
236 	 * This method allows applications to provide a TXFM that will be appended
237 	 * to the transform chain just prior to the application of the hash
238 	 * algorithm.
239 	 *
240 	 * @note This is primarily for debugging.  It should not be used to modify the
241 	 * contents of the byte stream.
242 	 *
243 	 * @param t The TXFM element to insert.
244 	 */
245 
246 	void setPreHashTXFM(TXFMBase * t);
247 
248    /**
249     * \brief Set the Id attribute of the DSIGReference
250     *
251     * This method allows applications to set the Id attribute of the DSIGReference
252     * as described in http://www.w3.org/TR/xmldsig-core/#sec-Reference.
253     *
254     *
255     * @param id The value for this reference.
256     */
257    void setId(const XMLCh *id);
258 
259    /**
260     * \brief Set the Type attribute of the DSIGReference
261     *
262     * This method allows applications to set the Type attribute of the DSIGReference
263     * as described in http://www.w3.org/TR/xmldsig-core/#sec-Reference.
264     *
265     *
266     * @param type The value for this reference.
267     */
268    void setType(const XMLCh *type);
269 	//@}
270 
271 	/** @name Getting Information */
272 	//@{
273 
274 	/**
275 	 * \brief Create an input stream based on the digested byte stream.
276 	 *
277 	 * This method allows applications to read the fully canonicalised
278 	 * byte stream that is hashed for a reference.
279 	 *
280 	 * All transforms are performed up to the point where they would
281 	 * normally be fed into the Digest function.
282 	 *
283 	 * @returns A BinInputSource of the canonicalised SignedInfo
284 	 */
285 
286 	XSECBinTXFMInputStream * makeBinInputStream(void) const;
287 
288 	/**
289 	 * \brief Return the URI string of the Reference.
290 	 *
291 	 * @returns A pointer to the buffer (owned by the Reference) containing
292 	 * the value of the URI stored inthe reference
293 	 */
294 
295 	const XMLCh * getURI() const;
296 
297     /**
298      * \brief Get the Digest Algorithm URI
299      *
300      * @returns the URI associated with the Algorithm used to generate
301      * the digest
302      */
303 
getAlgorithmURI() const304     const XMLCh * getAlgorithmURI() const {
305         return mp_algorithmURI;
306     }
307 
308 	/**
309 	 * \brief Obtain the transforms for this reference
310 	 *
311 	 * Get the DSIGTransformList object for this reference.  Can be used to
312 	 * obtain information about the transforms and also change the the transforms
313 	 */
314 
getTransforms(void) const315 	DSIGTransformList * getTransforms(void) const {
316 		return mp_transformList;
317 	}
318 
319 	/**
320 	 * \brief Determine whether the reference is a manifest
321 	 *
322 	 * @returns true iff the Reference element is a Manifest reference
323 	 */
324 
325 	bool isManifest() const;
326 
327 	/**
328 	 * \brief Get the Manifest
329 	 *
330 	 * @returns The ReferenceList containing the references in the Manifest
331 	 * list of this reference element.
332 	 */
333 
334 	DSIGReferenceList * getManifestReferenceList() const;		// Return list of references for a manifest object
335 
336 
337 	//@}
338 
339 	/** @name Message Digest/Hash manipulation */
340 	//@{
341 
342 	/**
343 	 * \brief Calculate the Hash  value of a reference
344 	 *
345 	 * Takes the Reference URI, performs all the transforms and finally
346 	 * calculates the Hash value of the data using the Digest algorithm
347 	 * indicated in the reference
348 	 *
349 	 * @param toFill A Buffer that the raw hash will be copied into.
350 	 * @param maxToFill Maximum number of bytes to place in the buffer
351 	 * @returns The number of bytes copied into the buffer
352 	 */
353 
354 	unsigned int calculateHash(XMLByte * toFill, unsigned int maxToFill) const;
355 
356 	/**
357 	 * \brief Read the hash from the Reference element.
358 	 *
359 	 * Reads the Base64 encoded element from the Reference element.
360 	 * The hash is then translated from Base64 back into raw form and
361 	 * written into the indicated buffer.
362 	 *
363 	 * @param toFill Pointer to the buffer where the raw hash will be written
364 	 * @param maxToFill Maximum bytes to write to the buffer
365 	 * @returns Number of bytes written
366 	 */
367 
368 	unsigned int readHash(XMLByte *toFill, unsigned int maxToFill) const;
369 
370 	/**
371 	 * \brief Validate the Reference element
372 	 *
373 	 * Performs a #calculateHash() and a #readHash() and then compares the
374 	 * results.
375 	 *
376 	 * @returns true iff the hash of the data matches the hash stored
377 	 * in the reference.
378 	 */
379 
380 	bool checkHash() const;
381 
382 	/**
383 	 * \brief Set the value of the hash in the Reference
384 	 *
385 	 * Hashes the data referenced by the element and then writes
386 	 * the Base64 encoded hash value into the Reference.
387 	 *
388 	 */
389 
390 	void setHash();
391 
392 	//@}
393 
394 	/** @name Helper (static) Functions */
395 	//@{
396 
397 	/**
398 	 * \brief Create a Transformer chain
399 	 *
400 	 * Given a TransformList create the corresponding TXFM chain to allow
401 	 * the caller to read the reference byte stream
402 	 *
403 	 * @note This method is primarily for use within the XSEC library.
404 	 * Users wishing to get the byte stream should use the #makeBinInputStream
405 	 * method instead.
406 	 *
407 	 * @param input The input transformer to which the TXFMs will be applied to
408 	 * This is generally created from the URI attribute of the reference.
409 	 * @param lst The list of Transform elements from which to build the
410 	 * transformer list.
411 	 * @returns The <B>end</B> of the newly build TXFM chain.  This can be
412 	 * read from using TXFMBase::readBytes() to give the end result of the
413 	 * transforms.
414 	 */
415 
416 	static TXFMChain * createTXFMChainFromList(TXFMBase * input,
417 							DSIGTransformList * lst);
418 
419 	/**
420 	 * \brief Load a Transforms list from the \<Transforms\> DOMNode.
421 	 *
422 	 * Reads the data from the XML data stored in the DOM and create
423 	 * the associated DSIGTrasnformList.
424 	 *
425 	 * @param transformsNode Starting node in the DOM
426 	 * @param formatter The formatter to be used to move from XMLCh to strings
427 	 * @param env Environment in which to operate
428 	 * @returns A pointer to the created list.
429 	 */
430 
431 	static DSIGTransformList * loadTransforms(
432 							XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *transformsNode,
433 							XSECSafeBufferFormatter * formatter,
434 							const XSECEnv * env);
435 
436 	/**
437 	 * \brief Create a starting point for a TXFM Chain.
438 	 *
439 	 * Uses the provided URI to find the base data that the Transformer chain
440 	 * will be built upon.
441 	 *
442 	 * @param doc The document that the signature is based on (used for local URIs)
443 	 * @param URI The URI to build the base from
444 	 * @param env The environment the signature is operating in
445 	 * @returns A base TXFM element.
446 	 */
447 
448 	static TXFMBase * getURIBaseTXFM(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * doc,
449 									const XMLCh * URI,
450 									const XSECEnv * env);
451 
452 	/**
453 	 * \brief Load a series of references.
454 	 *
455 	 * Takes a series of \<Reference\> elements in a DOM structure
456 	 * and creates the corresponding ReferenceList object.
457 	 *
458 	 * @note Internal function - meant for use by the library
459 	 *
460 	 * @param env The environment in which this reference resides
461 	 * @param firstReference First reference in DOM structure
462 	 * @returns the created list.
463 	 */
464 
465 	static DSIGReferenceList *loadReferenceListFromXML(const XSECEnv * env,
466 													   XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *firstReference);
467 
468 	/**
469 	 * \brief Validate a list of references.
470 	 *
471 	 * Runs through a reference list, calling verify() on each and
472 	 * setting the ErrroStrings for any errors found
473 	 *
474 	 * @param lst The list to verify
475 	 * @param errorStr The string to append any errors found to
476 	 * @returns true iff all the references validate successfully.
477 	 */
478 
479 	static bool verifyReferenceList(const DSIGReferenceList * lst, safeBuffer &errorStr);
480 
481 	/**
482 	 * \brief Hash a reference list
483 	 *
484 	 * Run through a list of references and calculate the hash value of each
485 	 * element.  Finally set the Base64 encoded string according to the newly
486 	 * calcuated hash.
487 	 *
488 	 * @note This is an internal library function and should not be called directly.
489 	 *
490 	 * @param list The list of references
491 	 * @param interlocking If set to false, the library will assume there
492 	 * are no inter-related references.  The algorithm for determining this
493 	 * internally is very primitive and CPU intensive, so this is a method to
494 	 * bypass the checks.
495 	 */
496 	static void hashReferenceList(const DSIGReferenceList * list, bool interlocking = true);
497 
498 	//@}
499 
500 private:
501 
502 	// Internal functions
503 	void createTransformList(void);
504 	void addTransform(
505 		DSIGTransform * txfm,
506 		XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * txfmElt
507 	);
508 
509 
510 	XSECSafeBufferFormatter		* mp_formatter;
511 	XERCES_CPP_NAMESPACE_QUALIFIER DOMNode
512 								* mp_referenceNode;		// Points to start of document where reference node is
513 	mutable TXFMBase				* mp_preHash;			// To be used pre-hash
514 	DSIGReferenceList			* mp_manifestList;		// The list of references in a manifest
515 	const XMLCh					* mp_URI;				// The URI String
516 	bool						m_isManifest;			// Does this reference a manifest?
517 	XERCES_CPP_NAMESPACE_QUALIFIER DOMNode
518 								* mp_transformsNode;
519 	XERCES_CPP_NAMESPACE_QUALIFIER DOMNode
520 								* mp_hashValueNode;		// Node where the Hash value is stored
521 	const XSECEnv				* mp_env;
522 	DSIGTransformList			* mp_transformList;		// List of transforms
523 	const XMLCh					* mp_algorithmURI;		// Hash algorithm for this reference
524 
525 	bool                        m_loaded;
526 
527 	DSIGReference();
528 
529 	/*\@}*/
530 
531 	friend class DSIGSignedInfo;
532 };
533 
534 #endif /* #define DSIGREFERENCE_INCLUDE */
535