xsec/dsig/DSIGSignature.hpp (124 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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$ * */ #ifndef DSIGSIGNATURE_INCLUDE #define DSIGSIGNATURE_INCLUDE // XSEC Includes #include <xsec/utils/XSECSafeBufferFormatter.hpp> #include <xsec/dsig/DSIGTransform.hpp> #include <xsec/dsig/DSIGKeyInfoList.hpp> #include <xsec/dsig/DSIGConstants.hpp> #include <xsec/dsig/DSIGSignedInfo.hpp> // Xerces Includes #include <xercesc/dom/DOM.hpp> 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. * * <p>The DSIGSignature class is used to manipulate and verify * \<signature\> blocks. It should only ever be created via the * XSECProvider class.</p> * */ class XSEC_EXPORT DSIGSignature { protected: /** @name Constructors and Destructors */ //@{ /** * \brief Contructor for use with existing XML signatures or templates. * * <p>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.</p> * * <p>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.</p> * * @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); virtual ~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(); /** * \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. * * <p>The <I>verify</I> function will validate the signature of an XML document * previously loaded into the DSIGSignature structure via a <I>load</I>.</p> * * <p>It performs the following operations : </p> * <ul> * <li>Iterate through each reference and validate the hash; * <li>Iterate through references contained in \<manifest\> elements; * <li>Calculate the hash of the \<SignedInfo\> element; and * <li>Validate the signature of the hash previously calculated. * </ul> * * @returns true/false * <ul> * <li><b>true</b> = Signature (and all references) validated correctly. * <li><b>false</b> = Signature validation failed. An error list can be found via a * call to #getErrMsgs. * </ul> * @see #load * @see #getErrMsgs */ bool verify() const; /** * \brief Verify a signature is valid (skip references). * * <p>This function is almost the same as #verify except it will skip the * reference checks. * * @see #load * @see #verify */ bool verifySignatureOnly() const; /** * \brief Sign a DSIGSignature DOM structure. * * <p>The #sign function will create the reference hash values and signature * value in a DOM structure previously created via a #load or #createBlankSignature * call </p> * * <p>It performs the following operations : </p> * <ul> * <li>Iterate through each reference, calculate and set the hash value; * <li>Iterate through references contained in \<manifest\> elements and set their values; * <li>Calculate the hash of the \<SignedInfo\> element; and * <li>Calculate (and set) the signature value given the hash previously calculated. * </ul> * * @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(); //@} /** @name Functions to create and manipulate signature elements. */ //@{ /** * \brief Set the prefix be used for the DSIG namespace. * * <p>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.</p> * * <p>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 \<Signature\> element will have a namespace attribute added of</p> * * <p>xmlns:ds="http://www.w3.org/2000/09/xmldsig#"</p> * * <p>If no prefix has been set, this attribute will be set as the default namespace</p> * * @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. * * <p>xmlns:ds="http://www.w3.org/2001/10/xml-exc-c14n#"</p> * * 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 * * <p>xmlns:ds="http://www.w3.org/2002/06/xmldsig-filter2"</p> * * 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() const; /** * \brief Create a \<Signature\> DOM structure. * * <p>The DOM structure created is still divorced from the document. The callee * needs to take the returned \<Signature\> Element node and insert it at the * appropriate place in their document.</p> * * <p>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 \<Signature\> 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 Add a new reference to the end of the list of \<Reference\> nodes. * * <p>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.</p> * * @note The XSEC Library currently makes very little use of <em>type</em> * attributes in \<Reference\> 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 ); /** * \brief Remove a reference from the signature * * Removes the reference at the index point and returns a pointer * to the reference removed. * * @note This also releases ownership. It is the responsibility of * the caller to ensure the reference is deleted. * * @note This removes the reference from the Signature * * @param index Point in the list to remove */ DSIGReference* removeReference(DSIGReferenceList::size_type index); //@} /** @name General and Information functions. */ //@{ /** * \brief Get the hash of the Signed Value * * Function to calculate and return the hash of the \<SignedInfo\> * structures (after the canonicalization defined by * \<CanonicalizationMethod\> 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) const; /** * \brief Get the hash of the Signed Value * * Function to calculate and return the hash of the \<SignedInfo\> * structures (after the canonicalization defined by * \<CanonicalizationMethod\> 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) const; /** * \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(); /** * \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 */ const DSIGReferenceList* getReferenceList() const; /** * \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() 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() const; /** * \brief Get the NS Prefix being used for DSIG elements. * * @returns A pointer to the buffer holding the prefix * @see #setDSIGNSPrefix * */ const XMLCh* getDSIGNSPrefix() const; /** * \brief Get the NS being used for EC nodes * * @returns A pointer to the buffer holding the prefix * @see #setECNSPrefix */ const XMLCh* getECNSPrefix() const; /** * \brief Get the NS being used for XPath Filter2 nodes * * @returns A pointer to the buffer holding the prefix * @see #setXPFNSPrefix */ const XMLCh* getXPFNSPrefix() const; /** * \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() const {return mp_doc;} /** * \brief Get canonicalisation algorithm * * Returns the canonicalisation algorithm that will be/is used * to canonicalise the \<SignedInfo\> element prior to hash/sign * * @returns The canonicalisation method */ const XMLCh* getCanonicalizationMethod() const {return mp_signedInfo != NULL ? mp_signedInfo->getCanonicalizationMethod() : NULL;} /** * \brief Get the Algorithm URI * * @returns the URI associated with the Algorithm used to generate * the signature */ const XMLCh* getAlgorithmURI() const; /** * \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) const {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() const {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() const; /** * \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() const; //@} /** @name KeyInfo Element Manipulation */ //@{ /** * \brief Get the list of \<KeyInfo\> elements. * * <p>This function recovers list that contains the KeyInfo elements * read in from the DOM document.</p> * * <p>This list should be used by calling applications to determine what key * is appropriate for validating (or even signing) the Signature.</p> * * @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 Get the list of \<KeyInfo\> elements. * * <p>This function recovers list that contains the KeyInfo elements * read in from the DOM document.</p> * * <p>This list should be used by calling applications to determine what key * is appropriate for validating (or even signing) the Signature.</p> * * @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 */ const DSIGKeyInfoList* getKeyInfoList() const {return &m_keyInfoList;} /** * \brief Clear out all KeyInfo elements in the signature. * * This function will delete all KeyInfo elements from both the DSIGSignature * object <em>and the associated DOM</em>. * */ void clearKeyInfo(); /** * \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(); /** * \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 \<Object\> 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(); /** * \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() const; /** * \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); /** * \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. */ const DSIGObject* getObjectItem(int i) const; //@} /** @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 disabled. * * @warning The default has been changed from earlier versions of the library * to address the security risk of assuming IDness based on name. * * @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() const; /** * \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<DSIGObject*> ObjectVectorType; #else typedef std::vector<DSIGObject*> ObjectVectorType; #endif // Internal functions void createKeyInfoElement(); bool verifySignatureOnlyInternal() const; TXFMChain* getSignedInfoInput() const; // Initialisation static void Initialise(); 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; mutable safeBuffer m_errStr; // Environment XSECEnv* mp_env; // The signing/verifying key mutable 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 */