Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
301 lines
12 KiB
C#
301 lines
12 KiB
C#
// SignedSignatureProperties.cs
|
||
//
|
||
// XAdES Starter Kit for Microsoft .NET 3.5 (and above)
|
||
// 2010 Microsoft France
|
||
// Published under the CECILL-B Free Software license agreement.
|
||
// (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt)
|
||
//
|
||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||
// WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
||
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
|
||
// THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE
|
||
// AND INFORMATION REMAINS WITH THE USER.
|
||
//
|
||
|
||
using System;
|
||
using System.Security.Cryptography;
|
||
using System.Xml;
|
||
|
||
namespace Microsoft.Xades
|
||
{
|
||
/// <summary>
|
||
/// The properties that qualify the signature itself or the signer are
|
||
/// included as content of the SignedSignatureProperties element
|
||
/// </summary>
|
||
public class SignedSignatureProperties
|
||
{
|
||
#region Private variables
|
||
private DateTimeOffset signingTime;
|
||
private SigningCertificate signingCertificate;
|
||
private SignaturePolicyIdentifier signaturePolicyIdentifier;
|
||
private SignatureProductionPlace signatureProductionPlace;
|
||
private SignerRole signerRole;
|
||
#endregion
|
||
|
||
#region Public properties
|
||
/// <summary>
|
||
/// The signing time property specifies the time at which the signer
|
||
/// performed the signing process. This is a signed property that
|
||
/// qualifies the whole signature. An XML electronic signature aligned
|
||
/// with the present document MUST contain exactly one SigningTime element.
|
||
/// </summary>
|
||
public DateTimeOffset SigningTime
|
||
{
|
||
get
|
||
{
|
||
return this.signingTime;
|
||
}
|
||
set
|
||
{
|
||
this.signingTime = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// The SigningCertificate property is designed to prevent the simple
|
||
/// substitution of the certificate. This property contains references
|
||
/// to certificates and digest values computed on them. The certificate
|
||
/// used to verify the signature shall be identified in the sequence;
|
||
/// the signature policy may mandate other certificates be present,
|
||
/// that may include all the certificates up to the point of trust.
|
||
/// This is a signed property that qualifies the signature. An XML
|
||
/// electronic signature aligned with the present document MUST contain
|
||
/// exactly one SigningCertificate.
|
||
/// </summary>
|
||
public SigningCertificate SigningCertificate
|
||
{
|
||
get
|
||
{
|
||
return this.signingCertificate;
|
||
}
|
||
set
|
||
{
|
||
this.signingCertificate = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// The signature policy is a set of rules for the creation and
|
||
/// validation of an electronic signature, under which the signature
|
||
/// can be determined to be valid. A given legal/contractual context
|
||
/// may recognize a particular signature policy as meeting its
|
||
/// requirements.
|
||
/// An XML electronic signature aligned with the present document MUST
|
||
/// contain exactly one SignaturePolicyIdentifier element.
|
||
/// </summary>
|
||
public SignaturePolicyIdentifier SignaturePolicyIdentifier
|
||
{
|
||
get
|
||
{
|
||
return this.signaturePolicyIdentifier;
|
||
}
|
||
set
|
||
{
|
||
this.signaturePolicyIdentifier = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// In some transactions the purported place where the signer was at the time
|
||
/// of signature creation may need to be indicated. In order to provide this
|
||
/// information a new property may be included in the signature.
|
||
/// This property specifies an address associated with the signer at a
|
||
/// particular geographical (e.g. city) location.
|
||
/// This is a signed property that qualifies the signer.
|
||
/// An XML electronic signature aligned with the present document MAY contain
|
||
/// at most one SignatureProductionPlace element.
|
||
/// </summary>
|
||
public SignatureProductionPlace SignatureProductionPlace
|
||
{
|
||
get
|
||
{
|
||
return this.signatureProductionPlace;
|
||
}
|
||
set
|
||
{
|
||
this.signatureProductionPlace = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// According to what has been stated in the Introduction clause, an
|
||
/// electronic signature produced in accordance with the present document
|
||
/// incorporates: "a commitment that has been explicitly endorsed under a
|
||
/// signature policy, at a given time, by a signer under an identifier,
|
||
/// e.g. a name or a pseudonym, and optionally a role".
|
||
/// While the name of the signer is important, the position of the signer
|
||
/// within a company or an organization can be even more important. Some
|
||
/// contracts may only be valid if signed by a user in a particular role,
|
||
/// e.g. a Sales Director. In many cases who the sales Director really is,
|
||
/// is not that important but being sure that the signer is empowered by his
|
||
/// company to be the Sales Director is fundamental.
|
||
/// </summary>
|
||
public SignerRole SignerRole
|
||
{
|
||
get
|
||
{
|
||
return this.signerRole;
|
||
}
|
||
set
|
||
{
|
||
this.signerRole = value;
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region Constructors
|
||
/// <summary>
|
||
/// Default constructor
|
||
/// </summary>
|
||
public SignedSignatureProperties()
|
||
{
|
||
this.signingTime = DateTimeOffset.MinValue;
|
||
this.signingCertificate = new SigningCertificate();
|
||
//this.signaturePolicyIdentifier = new SignaturePolicyIdentifier();
|
||
this.signatureProductionPlace = new SignatureProductionPlace();
|
||
this.signerRole = new SignerRole();
|
||
}
|
||
#endregion
|
||
|
||
#region Public methods
|
||
/// <summary>
|
||
/// Check to see if something has changed in this instance and needs to be serialized
|
||
/// </summary>
|
||
/// <returns>Flag indicating if a member needs serialization</returns>
|
||
public bool HasChanged()
|
||
{ //Should always be serialized
|
||
bool retVal = false;
|
||
|
||
retVal = true;
|
||
|
||
return retVal;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Load state from an XML element
|
||
/// </summary>
|
||
/// <param name="xmlElement">XML element containing new state</param>
|
||
public void LoadXml(System.Xml.XmlElement xmlElement)
|
||
{
|
||
XmlNamespaceManager xmlNamespaceManager;
|
||
XmlNodeList xmlNodeList;
|
||
|
||
if (xmlElement == null)
|
||
{
|
||
throw new ArgumentNullException("xmlElement");
|
||
}
|
||
|
||
xmlNamespaceManager = new XmlNamespaceManager(xmlElement.OwnerDocument.NameTable);
|
||
xmlNamespaceManager.AddNamespace("xsd", XadesSignedXml.XadesNamespaceUri);
|
||
|
||
xmlNodeList = xmlElement.SelectNodes("xsd:SigningTime", xmlNamespaceManager);
|
||
if (xmlNodeList.Count == 0)
|
||
{
|
||
throw new CryptographicException("SigningTime missing");
|
||
}
|
||
this.signingTime = XmlConvert.ToDateTime(xmlNodeList.Item(0).InnerText, XmlDateTimeSerializationMode.Utc);
|
||
|
||
xmlNodeList = xmlElement.SelectNodes("xsd:SigningCertificate", xmlNamespaceManager);
|
||
if (xmlNodeList.Count == 0)
|
||
{
|
||
throw new CryptographicException("SigningCertificate missing");
|
||
}
|
||
this.signingCertificate = new SigningCertificate();
|
||
this.signingCertificate.LoadXml((XmlElement)xmlNodeList.Item(0));
|
||
|
||
xmlNodeList = xmlElement.SelectNodes("xsd:SignaturePolicyIdentifier", xmlNamespaceManager);
|
||
// TODO: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
// <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
//if (xmlNodeList.Count == 0)
|
||
//{
|
||
// throw new CryptographicException("SignaturePolicyIdentifier missing");
|
||
//}
|
||
//this.signaturePolicyIdentifier = new SignaturePolicyIdentifier();
|
||
//this.signaturePolicyIdentifier.LoadXml((XmlElement)xmlNodeList.Item(0));
|
||
if (xmlNodeList.Count != 0)
|
||
{
|
||
this.signaturePolicyIdentifier = new SignaturePolicyIdentifier();
|
||
this.signaturePolicyIdentifier.LoadXml((XmlElement)xmlNodeList.Item(0));
|
||
}
|
||
|
||
xmlNodeList = xmlElement.SelectNodes("xsd:SignatureProductionPlace", xmlNamespaceManager);
|
||
if (xmlNodeList.Count != 0)
|
||
{
|
||
this.signatureProductionPlace = new SignatureProductionPlace();
|
||
this.signatureProductionPlace.LoadXml((XmlElement)xmlNodeList.Item(0));
|
||
}
|
||
else
|
||
{
|
||
this.signatureProductionPlace = null;
|
||
}
|
||
|
||
xmlNodeList = xmlElement.SelectNodes("xsd:SignerRole", xmlNamespaceManager);
|
||
if (xmlNodeList.Count != 0)
|
||
{
|
||
this.signerRole = new SignerRole();
|
||
this.signerRole.LoadXml((XmlElement)xmlNodeList.Item(0));
|
||
}
|
||
else
|
||
{
|
||
this.signerRole = null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns the XML representation of the this object
|
||
/// </summary>
|
||
/// <returns>XML element containing the state of this object</returns>
|
||
public XmlElement GetXml()
|
||
{
|
||
XmlDocument creationXmlDocument;
|
||
XmlElement retVal;
|
||
XmlElement bufferXmlElement;
|
||
|
||
creationXmlDocument = new XmlDocument();
|
||
retVal = creationXmlDocument.CreateElement("xades", "SignedSignatureProperties", XadesSignedXml.XadesNamespaceUri);
|
||
|
||
if (this.signingTime == DateTimeOffset.MinValue)
|
||
{
|
||
this.signingTime = DateTime.Now;
|
||
}
|
||
bufferXmlElement = creationXmlDocument.CreateElement("xades", "SigningTime", XadesSignedXml.XadesNamespaceUri);
|
||
bufferXmlElement.InnerText = signingTime.ToString(SigningTimeFormat);
|
||
retVal.AppendChild(bufferXmlElement);
|
||
|
||
if (this.signingCertificate != null && this.signingCertificate.HasChanged())
|
||
{
|
||
retVal.AppendChild(creationXmlDocument.ImportNode(this.signingCertificate.GetXml(), true));
|
||
}
|
||
else
|
||
{
|
||
throw new CryptographicException("SigningCertificate element missing in SignedSignatureProperties");
|
||
}
|
||
|
||
// TODO: <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
//if (this.signaturePolicyIdentifier != null && this.signaturePolicyIdentifier.HasChanged())
|
||
//{
|
||
// retVal.AppendChild(creationXmlDocument.ImportNode(this.signaturePolicyIdentifier.GetXml(), true));
|
||
//}
|
||
//else
|
||
//{
|
||
// throw new CryptographicException("SignaturePolicyIdentifier element missing in SignedSignatureProperties");
|
||
//}
|
||
|
||
if (this.signatureProductionPlace != null && this.signatureProductionPlace.HasChanged())
|
||
{
|
||
retVal.AppendChild(creationXmlDocument.ImportNode(this.signatureProductionPlace.GetXml(), true));
|
||
}
|
||
|
||
if (this.signerRole != null && this.signerRole.HasChanged())
|
||
{
|
||
retVal.AppendChild(creationXmlDocument.ImportNode(this.signerRole.GetXml(), true));
|
||
}
|
||
|
||
return retVal;
|
||
}
|
||
#endregion
|
||
|
||
private const string SigningTimeFormat = "yyyy-MM-ddTHH:mm:ss.fffzzz";
|
||
}
|
||
}
|