/* * Copyright 2002-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * XSEC * * DSIGSignature := Class for checking and setting up signature nodes in a DSIG signature * * Author(s): Berin Lautenbach * * $Id: DSIGSignature.hpp 351395 2005-07-23 02:11:54Z blautenb $ * */ #ifndef DSIGSIGNATURE_INCLUDE #define DSIGSIGNATURE_INCLUDE // XSEC Includes #include #include #include #include #include // Xerces Includes #include class XSECEnv; class XSECBinTXFMInputStream; class XSECURIResolver; class XSECKeyInfoResolver; class DSIGKeyInfoValue; class DSIGKeyInfoX509; class DSIGKeyInfoName; class DSIGKeyInfoPGPData; class DSIGKeyInfoSPKIData; class DSIGKeyInfoMgmtData; class DSIGObject; /** * @ingroup pubsig */ /*\@{*/ /** * @brief The main class used for manipulating XML Digital Signatures. * *

The DSIGSignature class is used to manipulate and verify * \ blocks. It should only ever be created via the * XSECProvider class.

* */ class DSIG_EXPORT DSIGSignature { protected: /** @name Constructors and Destructors */ //@{ /** * \brief Contructor for use with existing XML signatures or templates. * *

Create a DSIGSignature object based on an already existing * DSIG Signature XML node. It is assumed that the underlying * DOM structure is in place and works correctly.

* *

It is required that the caller pass in the signature DOM Node * as there may be more than one signature in a document. The caller * needs to specify which signature tree is to be used.

* * @param doc The DOM document node in which the signature is embedded. * @param sigNode The DOM node (within doc) that is to be used as the base of the signature. * @see #load */ DSIGSignature(XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc, XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *sigNode); ~DSIGSignature(); //@} public: /** @name Load and Setup Functions */ //@{ /** * \brief Load the signature information from the DOM source. * * Used to tell the DSIGSignature object to read from the DOM tree * into local structures. Will throw various exceptions if it finds that * the DOM structure is not in line with the XML Signature standard. * */ void load(void); /** * \brief Externally set the signing/verification key * * Used prior to a verify or sign operation to set the signature key (public or * private respectively) to be used for the operation. * * @note Once passed in via this call, the key is owned by the Signature. It will * deleted when a new key is loaded or the signature is released. * * @see #verify * @see #sign */ void setSigningKey(XSECCryptoKey *k); //@} /** @name Signature Operations */ //@{ /** * \brief Verify that a signature is valid. * *

The verify function will validate the signature of an XML document * previously loaded into the DSIGSignature structure via a load.

* *

It performs the following operations :

*
    *
  • Iterate through each reference and validate the hash; *
  • Iterate through references contained in \ elements; *
  • Calculate the hash of the \ element; and *
  • Validate the signature of the hash previously calculated. *
* * @returns true/false *
    *
  • true = Signature (and all references) validated correctly. *
  • false = Signature validation failed. An error list can be found via a * call to #getErrMsgs. *
* @see #load * @see #getErrMsgs */ bool verify(void); /** * \brief Verify a signature is valid (skip references). * *

This function is almost the same as #verify except it will skip the * reference checks. * * @see #load * @see #verify */ bool verifySignatureOnly(void); /** * \brief Sign a DSIGSignature DOM structure. * *

The #sign function will create the reference hash values and signature * value in a DOM structure previously created via a #load or #createBlankSignature * call

* *

It performs the following operations :

*
    *
  • Iterate through each reference, calculate and set the hash value; *
  • Iterate through references contained in \ elements and set their values; *
  • Calculate the hash of the \ element; and *
  • Calculate (and set) the signature value given the hash previously calculated. *
* * @note The key to use for signing must have been set prior to call to sign using #setSigningKey * * @throws XSECException (for errors during the XML formatting and loading) * @throws XSECCryptoException (for errors during the cryptographic operations) * * @see #setSigningKey * @see #load * @see #getErrMsgs */ void sign(void); //@} /** @name Functions to create and manipulate signature elements. */ //@{ /** * \brief Set the prefix be used for the DSIG namespace. * *

When the XSEC library creates XML Element nodes, it uses the prefix here * for all nodes created. By default, the library assumes that the default * namespace is used.

* *

The #createBlankSignature function will use this prefix to setup the * dsig namespace. E.g. (assuming a call has been made to set the prefix to "ds") * the \ element will have a namespace attribute added of

* *

xmlns:ds="http://www.w3.org/2000/09/xmldsig#"

* *

If no prefix has been set, this attribute will be set as the default namespace

* * @see #createBlankSignature * @param prefix The UTF-16 encoided NS prefix to use for the XML * Digital Signature nodes */ void setDSIGNSPrefix(const XMLCh * prefix); /** * \brief Set the prefix be used for the Exclusive Canonicalisation namespace. * * The Exclusive Canonicalisation specification defines a new namespace for the * InclusiveNamespaces node. This function can be used to set the prefix * that the library will use when creating nodes within this namespace. * *

xmlns:ds="http://www.w3.org/2001/10/xml-exc-c14n#"

* * If no prefix is set, the default namespace will be used * * @see #createBlankSignature * @param prefix The UTF-16 encoided NS prefix to use for the XML * Exclusive Canonicalisation nodes */ void setECNSPrefix(const XMLCh * prefix); /** * \brief Set the prefix be used for the XPath-Filter2 namespace. * * The XPathFilter definition uses its own namespace. This * method can be used to set the prefix that the library will use * when creating elements in this namespace * *

xmlns:ds="http://www.w3.org/2002/06/xmldsig-filter2"

* * If no prefix is set, the default namespace will be used * * @see #createBlankSignature * @param prefix The UTF-16 encoided NS prefix to use for the XPath * filter nodes */ void setXPFNSPrefix(const XMLCh * prefix); /** * \brief Set Pretty Print * * The pretty print functions controls whether the library will output * CR/LF after the elements it adds to a document * * By default the library will do pretty printing (flag is true) * * @param flag Value to set for Pretty Printing (true = do pretty printing) */ void setPrettyPrint(bool flag); /** * \brief Tell caller whether PrettyPrinting is active * * @returns True if Pretty Printing is active, false if not */ bool getPrettyPrint(void); /** * \brief Create a \ DOM structure. * *

The DOM structure created is still divorced from the document. The callee * needs to take the returned \ Element node and insert it at the * appropriate place in their document.

* *

The signature is a skeleton only. There are no references or KeyInfo * elements inserted. However the DSIGSignature structures are set up with the * new information, so once an element has been created and a signing key has been * set, a call to #sign will sign appropriately. * * @note The digest method (hash method) set here is for the signing function only. * Different hash methods can be used for reference elements. * * @param doc The document the Signature DOM structure will be inserted into. * @param canonicalizationAlgorithmURI The canonicalisation method to use. * @param signatureAlgorithmURI The Signature algorithm (defined by URI) to use * @returns The newly created \ element that the caller should insert in * the document. */ XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *createBlankSignature( XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc, const XMLCh * canonicalizationAlgorithmURI, const XMLCh * signatureAlgorithmURI ); /** * \brief Create a \ DOM structure. * *

The DOM structure created is still divorced from the document. The callee * needs to take the returned \ Element node and insert it at the * appropriate place in their document.

* *

The signature is a skeleton only. There are no references or KeyInfo * elements inserted. However the DSIGSignature structures are set up with the * new information, so once an element has been created and a signing key has been * set, a call to #sign will sign appropriately. * * @note The digest method (hash method) set here is for the signing function only. * Different hash methods can be used for reference elements. * * @param doc The document the Signature DOM structure will be inserted into. * @param cm The canonicalisation method to use. * @param sm The signature algorithm to be used. * @param hm The Digest function to be used for the actual signatures. * @returns The newly created \ element that the caller should insert in * the document. * @deprecated Use the URI based creation method instead, as this supports * signature algorithms that are not known to the library directly. */ XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *createBlankSignature( XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc, canonicalizationMethod cm = CANON_C14N_NOC, signatureMethod sm = SIGNATURE_DSA, hashMethod hm = HASH_SHA1 ); /** * \brief Add a new reference to the end of the list of \ nodes. * *

Creates a new DSIGReference, adds it to the list of references handled * by the owning DSIGSignature and also creates the skeleton DOM structure into * the document.

* * @note The XSEC Library currently makes very little use of type * attributes in \ Elements. However this may of use to calling * applications. * * @see DSIGReference * @param URI The Data that this Reference node refers to. * @param hm The hashing (digest) method to be used for this reference * @param type A "type" string (as defined in XML Signature). * @returns The newly created DSIGReference element. * @deprecated Use the URI based creation method instead * */ DSIGReference * createReference( const XMLCh * URI, hashMethod hm = HASH_SHA1, char * type = NULL ); /** * \brief Add a new reference to the end of the list of \ nodes. * *

Creates a new DSIGReference, adds it to the list of references handled * by the owning DSIGSignature and also creates the skeleton DOM structure into * the document.

* * @note The XSEC Library currently makes very little use of type * attributes in \ Elements. However this may of use to calling * applications. * * @see DSIGReference * @param URI The Data that this Reference node refers to. * @param hm The hashing (digest) method to be used for this reference * @param type A "type" string (as defined in XML Signature). * @returns The newly created DSIGReference element. * @deprecated Use the URI based creation method instead * */ DSIGReference * createReference( const XMLCh * URI, const XMLCh * hashAlgorithmURI, const XMLCh * type = NULL ); //@} /** @name General and Information functions. */ //@{ /** * \brief Get the hash of the Signed Value * * Function to calculate and return the hash of the \ * structures (after the canonicalization defined by * \ and the reference hashes have been performed). * * @param hashBuf Buffer to place the raw hash in. * @param hashBufLen The length of the buffer * @returns The length of the hash that was placed in hashBuf * */ unsigned int calculateSignedInfoAndReferenceHash(unsigned char * hashBuf, unsigned int hashBufLen); /** * \brief Get the hash of the Signed Value * * Function to calculate and return the hash of the \ * structures (after the canonicalization defined by * \ has been performed). * * @param hashBuf Buffer to place the raw hash in. * @param hashBufLen The length of the buffer * @returns The length of the hash that was placed in hashBuf * */ unsigned int calculateSignedInfoHash(unsigned char * hashBuf, unsigned int hashBufLen); /** * \brief Return the reference list for outside use. * * Returns a pointer to the list of references which can * then be read by the caller. * * @returns The referenceList */ DSIGReferenceList * getReferenceList(void); /** * \brief Create an input stream from SignedInfo. * * This method allows applications to read the fully canonicalised * byte stream that is hashed and signed. * * All transforms are performed up to the point where they would * normally be fed into the Digest function. * * @returns A BinInputSource of the canonicalised SignedInfo */ XSECBinTXFMInputStream * makeBinInputStream(void) const; /** * \brief Get the Error messages from the last #verify. * * Returns a list of text error messages from the last Signature * operation. Each error that occurred is in the buffer, separated * by new-lines. * * @note The buffer is owned by the DSIGSignature object - do not delete it * * @returns A pointer to the buffer containing the error strings. * */ const XMLCh * getErrMsgs(void); /** * \brief Get the NS Prefix being used for DSIG elements. * * @returns A pointer to the buffer holding the prefix * @see #setDSIGNSPrefix * */ const XMLCh * getDSIGNSPrefix(); /** * \brief Get the NS being used for EC nodes * * @returns A pointer to the buffer holding the prefix * @see #setECNSPrefix */ const XMLCh * getECNSPrefix(); /** * \brief Get the NS being used for XPath Filter2 nodes * * @returns A pointer to the buffer holding the prefix * @see #setXPFNSPrefix */ const XMLCh * getXPFNSPrefix(); /** * \brief * * Get the DOM_Document that this Signature is operating within. * * Mainly used by the library itself. * * @returns The DOM_Document node. */ XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * getParentDocument() {return mp_doc;} /** * \brief Get canonicalisation algorithm * * Returns the canonicalisation algorithm that will be/is used * to canonicalise the \ element prior to hash/sign * * @returns The canonicalisation method */ canonicalizationMethod getCanonicalizationMethod(void) {return (mp_signedInfo != NULL ? mp_signedInfo->getCanonicalizationMethod() : CANON_NONE);} /** * \brief Get the hash method * * Obtain the hash (digest) algorithm that is used to generate a hash * of the canonicalised \ element. * * @returns the Hash (digest) Method */ hashMethod getHashMethod(void) {return (mp_signedInfo != NULL ? mp_signedInfo->getHashMethod() : HASH_NONE);} /** * \brief Get the signature method * * Obtain the algorithm that will be used to generate/check the signature * of the canonicalised and hashed \ element. * * @returns the Signature method */ signatureMethod getSignatureMethod(void) {return (mp_signedInfo != NULL ? mp_signedInfo->getSignatureMethod() : SIGNATURE_NONE);} /** * \brief Get the Signature Value * * Returns the base64 string holding the signature value for this signature * * @returns the signature value string */ const XMLCh * getSignatureValue(void) const; /** * \brief Helper function for sub Classes. * * Returns the pointer to the formatter being used within the Signature * */ XSECSafeBufferFormatter * getSBFormatter(void) {return mp_formatter;} /** * \brief Set the interlocking references flag * * This flag controls whether the library will cater for "interlocking" * Reference nodes - where the hash of one reference depends on the * hash of another. * * As of Version 1.3, this is, by default, set to false, as it is * fairly unusual to find a Reference node that has as an input the * digest value of another reference node. By setting this value to * true, the library will first calculate all hash values, and then * verify the hash values. If any are incorrect (caused by one * the value of one reference being changed *after* it was used as * the input to another), then the hash values are recalculated. This * is repeated until the reference list "settles". * * @param flag true for interlocking references, false for standalone */ void setInterlockingReferences(bool flag) {m_interlockingReferences = flag;} /** * \brief Get the interlocking references flag * * This flag controls whether the library will cater for "interlocking" * Reference nodes - where the hash of one reference depends on the * hash of another. * * As of Version 1.3, this is, by default, set to false, as it is * fairly unusual to find a Reference node that has as an input the * digest value of another reference node. By setting this value to * true, the library will first calculate all hash values, and then * verify the hash values. If any are incorrect (caused by one * the value of one reference being changed *after* it was used as * the input to another), then the hash values are recalculated. This * is repeated until the reference list "settles". * * @return Value of flag - true for interlocking references, false for standalone */ bool getInterlockingReferences(void) {return m_interlockingReferences;} //@} /** @name Resolver manipulation */ //@{ /** * \brief Register a URIResolver * * Registers a URIResolver to be used by the Signature when dereferencing * a URI in a Reference element * */ void setURIResolver(XSECURIResolver * resolver); /** * \brief Return a pointer to the resolver being used * * @returns A pointer to the URIResolver registered in this signature */ XSECURIResolver * getURIResolver(void); /** * \brief Register a KeyInfoResolver * * Registers a KeyInfoResolver to be used by the Signature when * it needs to find a key to be used to validate a signature * */ void setKeyInfoResolver(XSECKeyInfoResolver * resolver); /** * \brief Return a pointer to the resolver being used * * @returns A pointer to the KeyInfoResolver registered in this signature */ XSECKeyInfoResolver * getKeyInfoResolver(void); //@} /** @name KeyInfo Element Manipulation */ //@{ /** * \brief Get the list of \ elements. * *

This function recovers list that contains the KeyInfo elements * read in from the DOM document.

* *

This list should be used by calling applications to determine what key * is appropriate for validating (or even signing) the Signature.

* * @todo The KeyInfo process is very primitive. An interface needs to be * created to allow application developers to install an object into the Signature * that the Signature can call on to translate KeyInfo lists into a Key. * @returns A pointer to the DSIGKeyInfoList object held by the DSIGSignature */ DSIGKeyInfoList * getKeyInfoList() {return &m_keyInfoList;} /** * \brief Clear out all KeyInfo elements in the signature. * * This function will delete all KeyInfo elements from both the DSIGSignature * object and the associated DOM. * */ void clearKeyInfo(void); /** * \brief Append a DSA KeyValue element * * Add a new KeyInfo element for a DSA Value * * @param P Base64 encoded value of P * @param Q Base64 encoded value of Q * @param G Base64 encoded value of G * @param Y Base64 encoded value of Y * @returns A pointer to the created object. */ DSIGKeyInfoValue * appendDSAKeyValue(const XMLCh * P, const XMLCh * Q, const XMLCh * G, const XMLCh * Y); /** * \brief Append a RSA KeyValue element * * Add a new KeyInfo element for a RSA Value * * @param modulus Base64 encoded value of the modulus * @param exponent Base64 encoded value of exponent * @returns A pointer to the created object. */ DSIGKeyInfoValue * appendRSAKeyValue(const XMLCh * modulus, const XMLCh * exponent); /** * \brief Append a X509Data element. * * Add a new KeyInfo element for X509 data. * * @note The added element is empty. The caller must make use of the * returned object to set the required values. * * @returns A pointer to the created object. */ DSIGKeyInfoX509 * appendX509Data(void); /** * \brief Append a KeyName element. * * Add a new KeyInfo element for a key name. * * @param name The name of the key to set in the XML * @param isDName Treat the name as a Distinguished name and encode accordingly * @returns A pointer to the created object */ DSIGKeyInfoName * appendKeyName(const XMLCh * name, bool isDName = false); /** * \brief Append a PGPData element. * * Add a new KeyInfo element for a PGP key. * * @param id The ID of the key to set in the XML (base64 encoded - NULL if none) * @param packet The Packet information to set in the XML (base64 encoded - * NULL if none) * @returns A pointer to the created object */ DSIGKeyInfoPGPData * appendPGPData(const XMLCh * id, const XMLCh * packet); /** * \brief Append a SPKIData element * * Add a new KeyInfo element for a set of SPKI S-expressions * * @param sexp The initial S-expression to set in the SPKIData element * @returns A pointer to the created object */ DSIGKeyInfoSPKIData * appendSPKIData(const XMLCh * sexp); /** * \brief Append a MgmtData element * * Add a new KeyInfo element for Management Data * * @param data The string to set in the MgmtData element * @returns A pointer to the created object */ DSIGKeyInfoMgmtData * appendMgmtData(const XMLCh * data); //@} /** @name Object handling */ //@{ /** * \brief Append an object container * * Create a new Object (i.e. a Signature \ which is a container * element used to hold information that needs to be signed within the * signature - i.e. in enveloping mode * * @returns the newly created DSIGObject */ DSIGObject * appendObject(void); /** * \brief Find the number of ds:Object nodes within the Signature * * @returns the number of ds:Object nodes held in the Signature, 0 if none */ int getObjectLength(void); /** * \brief Get a particular ds:Object from within the Signature * * @returns the ith Object from the list of ds:Object nodes in the signature. * Items are ordered in tree order. */ DSIGObject * getObjectItem(int i); //@} /** @name ID handling */ //@{ /** * \brief Set Id finding behaviour * * The library de-references "#obj" URI references to ID attributes within * a DOM document. Currently, the library first uses DOM calls to find if * the Id has been properly set within the document via the parser or one * of the DOM Level 3 calls to set an Id. * * If no Id is found of the correct name, the library then starts searching * for attributes of a given name with the required value. This list defaults * to "id" and "Id", but can be modified via a call to addIdAttributeName() * * The setIdByAttributeName call enables or disables the second part of the Id * search. I.e. when the Id doesn't exist as an attribute of Type=ID, whether or * not to search for an attribute of a name in the list of names. By default * this behaviour is enabled. * * @warning This is currently enabled by default for backwards compatibility * reasons only. Future version may reverse this and ship disabled by default, as * this behaviour is a potential security risk. * * @param flag Enable (true) or Disable (false) searching for Id attributes by name */ void setIdByAttributeName(bool flag); /** * \brief Determine Id finding behaviour * * Allows a caller to determine whether the library is currently searching for * Id attributes by name * * @returns The value of the IdByAttributeName flag */ bool getIdByAttributeName(void); /** * \brief Add an attribute name to be searched for when looking for Id attributes * * This allows a user to add an attribute name to be used to identify Id attributes * when they are not set to be of Type=ID in the DOM * * @note Two names are registered by default - "Id" and "id". These can be * removed by calling deregisterIdAttributeName * * @param name Name to append to the list of those used to find Id attributes */ void registerIdAttributeName(const XMLCh * name); /** * \brief Remove an attribute name to be searched for when looking for Id attributes * * This allows a user to de-register a particular name to be used to identify Id * attributes. * * @param name Name to remove from the list of those used to find Id attributes * @returns true if found and removed, false if was not in the list */ bool deregisterIdAttributeName(const XMLCh * name); /** * \brief Add an attribute name within a particular Namespace * to be searched for when looking for Id attributes * * This allows a user to add an attribute name to be used to identify Id attributes * when they are not set to be of Type=ID in the DOM * * @note Two names are registered by default - "Id" and "id". These can be * removed by calling deregisterIdAttributeName * * @param ns Namespace in which attribute will reside * @param name Name to append to the list of those used to find Id attributes */ void registerIdAttributeNameNS(const XMLCh * ns, const XMLCh * name); /** * \brief Remove an attribute name and ns to be searched for when looking for Id attributes * * This allows a user to de-register a particular name to be used to identify Id * attributes. * * @param ns Namespace in which attribute will reside * @param name Name to remove from the list of those used to find Id attributes * @returns true if found and removed, false if was not in the list */ bool deregisterIdAttributeNameNS(const XMLCh * ns, const XMLCh * name); //@} friend class XSECProvider; private: // For holding DSIGObject nodes #if defined(XSEC_NO_NAMESPACES) typedef vector ObjectVectorType; #else typedef std::vector ObjectVectorType; #endif // Internal functions void createKeyInfoElement(void); bool verifySignatureOnlyInternal(void); TXFMChain * getSignedInfoInput(void); // Initialisation static void Initialise(void); XSECSafeBufferFormatter * mp_formatter; bool m_loaded; // Have we already loaded? XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * mp_doc; XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * mp_sigNode; DSIGSignedInfo * mp_signedInfo; XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * mp_signatureValueNode; safeBuffer m_signatureValueSB; DSIGKeyInfoList m_keyInfoList; XERCES_CPP_NAMESPACE_QUALIFIER DOMNode * mp_KeyInfoNode; safeBuffer m_errStr; // Environment XSECEnv * mp_env; // The signing/verifying key XSECCryptoKey * mp_signingKey; // Resolvers XSECKeyInfoResolver * mp_KeyInfoResolver; // Objects ObjectVectorType m_objects; // Interlocking references bool m_interlockingReferences; // Not implemented constructors DSIGSignature(); friend class XSECPlatformUtils; /*\@}*/ }; #endif /* DSIGSIGNATURE_INCLUDE */