Extending System.Security.Cryptography.Xml for Custom Processing

for RuBoard

Extending System.Security.Cryptography.Xml for Custom Processing

Our last major topic for this chapter is a brief discussion of the extensibility mechanisms supported by the XMLDSIG classes. Extensibility takes two distinct forms in the System.Security.Cryptography.Xml namespace:

  • Support for new algorithms, including signature functions, hash algorithms, canonicalization algorithms, and XML transforms

  • Support for extending the KeyInfo and Reference processing behavior of the SignedXml class

Recall from the "XMLDSIG Design Principles and Modes of Use" section earlier in the chapter that XMLDSIG was architected to support the use of arbitrary cryptographic algorithms. This requirement is reflected in the XMLDSIG schema in the use of URIs to identify algorithms throughout the defined element structures. The XMLDSIG classes handle arbitrary algorithms by leveraging the cryptographic configuration system described in the "Administering Cryptography Settings" section in Chapter 22. Whenever an XMLDSIG class needs to resolve a URI into an algorithm object, the resolution is performed by calling the CryptoConfig.CreateFromName method. Additionally, the CryptoConfig class is also used to resolve transform URIs into Transform subclasses and ds:KeyInfo sub-elements into subclasses of KeyInfoClause . A complete list of the default mappings from URIs to objects relevant to XMLDSIG is included in Table 32.10.

Table 32.10. Default CryptoConfig.CreateFromName Mappings Related to XMLDSIG Objects

Name :

Class:

http://www.w3.org/2000/09/xmldsig#dsa-sha1

System.Security.Cryptography.DSASignatureDescription

Name:

Class:

http://www.w3.org/2000/09/xmldsig#rsa-sha1

System.Security.Cryptography.RSAPKCS1SHA1SignatureDescription

Name:

Class:

http://www.w3.org/2000/09/xmldsig#rsa-sha1

System.Security.Cryptography.SHA1CryptoServiceProvider

Name:

Class:

http://www.w3.org/TR/2001/REC-xml-c14n-20010315

System.Security.Cryptography.Xml.XmlDsigC14NTransform

Name:

Class:

http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments

System.Security.Cryptography.Xml.XmlDsigC14NWithCommentsTransform

Name:

Class:

http://www.w3.org/2000/09/xmldsig#base64

System.Security.Cryptography.Xml.XmlDsigBase64Transform

Name:

Class:

http://www.w3.org/TR/1999/REC-xpath-19991116

System.Security.Cryptography.Xml.XmlDsigXPathTransform

Name:

Class:

http://www.w3.org/TR/1999/REC-xslt-19991116

System.Security.Cryptography.Xml.XmlDsigXsltTransform

Name:

Class:

http://www.w3.org/2000/09/xmldsig#enveloped-signature

System.Security.Cryptography.Xml.XmlDsigEnvelopedSignatureTransform

Name:

Class:

http://www.w3.org/2000/09/xmldsig#X509Data

System.Security.Cryptography.Xml.KeyInfoX509Data

Name:

Class:

http://www.w3.org/2000/09/xmldsig#KeyName

System.Security.Cryptography.Xml.KeyInfoName

Name:

Class:

http://www.w3.org/2000/09/xmldsig#KeyValue/DSAKeyValue

System.Security.Cryptography.Xml.DSAKeyValue

Name:

Class:

http://www.w3.org/2000/09/xmldsig#KeyValue/RSAKeyValue

System.Security.Cryptography.Xml.RSAKeyValue

Name:

Class:

http://www.w3.org/2000/09/xmldsig#RetrievalMethod

System.Security.Cryptography.Xml.KeyInfoRetrievalMethod

To add support for a new signature, hash, or transformation algorithm, simply add a mapping between the algorithm's URI identifier and the class implementing the algorithm to the cryptographySettings section of the machine-wide .NET Framework configuration file. KeyInfo sub-element handlers are identified by concatenating the XMLDSIG namespace URI http://www.w3.org/2000/09/xmldsig# , a space character, and then the tag name of the sub-element. So, for example, to add support for the PGPData sub-element of KeyInfo , you would need to add a mapping from the string value

http://www.w3.org/2000/09/xmldsig#PGPData

to a subclass of KeyInfoClause that handles PGPData elements. For sub-elements of the KeyValue element, the tag name must begin with KeyValue/ and then is followed by the tag name of the sub-element. (See the entries for RSAKeyValue and DSAKeyValue in Table 32.10 for details.)

In addition to new algorithm definitions, it is possible to subclass the SignedXml class and modify some of its default behaviors. Two methods on the SignedXml class are declared virtual ”the GetPublicKey and GetIdElement methods. These classes are used to generate candidate verification keys (usually based on KeyInfo information) and to resolve fragment URI references, respectively. The GetPublicKey() method is called by CheckSignature() and CheckSignatureReturningKey() to scan the contents of the KeyInfo element and suggest potential public keys to use to verify the signature. The implementation of SignedXml.GetPublicKey() enumerates the KeyInfo sub-elements looking for RSAKeyValue and DSAKeyValue elements. When it finds an RSA or DSA key in a KeyValue sub-element, it suggests that key be tried for verification. The method returns null to signal the end of its own enumeration when it runs out of keys to suggest.

The MySignedXml class shown in Listing 32.38 demonstrates how you can subclass SignedXml and define your own mechanism for suggesting possible verification keys. The GetPublicKey() method on MySignedXml uses information in KeyName elements in addition to RSAKeyValue and DSAKeyValue to try to find verification keys. In this sample, we assume that the signer and verifier have agreed that the string value contained in a KeyName element is the CryptoAPI key container name for a key located in the default "Type 1" Cryptographic Service Provider (CSP), and we use the techniques introduced in Chapter 31 for accessing and using CryptoAPI-based keys to find the key referenced in the KeyName element. When our new GetPublicKey() method finds a KeyInfoName object within KeyInfo , it extracts the Value property and calls CheckForPresenceOfKeyContainer to see if a key container of that name exists within the default CSP. If the container exists, a new RSACryptographicServiceProvider object is created referencing the specified key container by passing the container name within a CspParameters object. This new candidate verification key is then used by the other methods inherited from the SignedXml class to attempt verification of the digital signature.

Listing 32.38 Subclassing SignedXml to Change the Behavior of GetPublicKey()
 using System; using System.Security.Cryptography; using System.Security.Cryptography.Xml; using System.IO; using System.Xml; using System.Text; using System.Collections; using System.Runtime.InteropServices; public class MySignedXml : SignedXml {   IEnumerator m_keyInfoEnum = null;   public MySignedXml() : base() {   }   [DllImport("advapi32.dll", EntryPoint="CryptAcquireContext", CharSet=CharSet.Unicode)]   public static extern bool CryptAcquireContext(IntPtr phProv, String pszContainer, graphics/ccc.gif String pszProvider, int dwProvType, int dwFlags);   // Utility method for checking whether a specific key container   // is present in the default Type 1 CSP   private static bool CheckForPresenceOfKeyContainer(String keyContainerName) {     IntPtr phProv = new IntPtr(0);     bool result = CryptAcquireContext(phProv, keyContainerName, null, 1, 0);     return result;   }   protected override AsymmetricAlgorithm GetPublicKey() {     RSAKeyValue tempRSA;     DSAKeyValue tempDSA;     KeyInfoName tempName;     if (m_keyInfoEnum == null)       m_keyInfoEnum = KeyInfo.GetEnumerator();     // In our implementation, we move to the next KeyInfo clause     // which is an RSAKeyValue or a DSAKeyValue     while (m_keyInfoEnum.MoveNext()) {       tempRSA = m_keyInfoEnum.Current as RSAKeyValue;       if (tempRSA != null) return(tempRSA.Key);       tempDSA = m_keyInfoEnum.Current as DSAKeyValue;       if (tempDSA != null) return(tempDSA.Key);       tempName = m_keyInfoEnum.Current as KeyInfoName;       if (tempName != null) {         // Use the string value of the KeyInfoName as the public key container         // Check to see if the container is present         // We assume the key is an RSA key in this example         if (CheckForPresenceOfKeyContainer(tempName.Value)) {           // Create a new CspParameters referencing the key container           CspParameters cspParams = new CspParameters();           cspParams.KeyContainerName = tempName.Value;           // Create an RSACryptoServiceProvider referencing the key container           RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspParams);           return(rsa);         }       }     }     return(null);   } } 

By subclassing the SignedXml class, you can also override the default behavior of the GetIdElement method. GetIdElement is used by Reference objects to resolve fragment URI references, such as #ID1 . The default behavior of this method is to first attempt to resolve an ID value using the GetElementById method on the XmlDocument class. If that should fail, a secondary attempt is made to resolve the ID value by searching the document for nodes with an Id attribute equal to the supplied value. If you use an attribute other than Id to identify elements and do not include an XML Schema for your documents, you may have to override the default behavior of this method to make in-document references succeed.

for RuBoard


. NET Framework Security
.NET Framework Security
ISBN: 067232184X
EAN: 2147483647
Year: 2000
Pages: 235

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net