/// <summary> /// Reads XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-SignedInfo /// </summary> /// <param name="reader">a <see cref="XmlReader"/>positioned on a <SignedInfo> element.</param> /// <exception cref="ArgumentNullException">if <paramref name="reader"/> is null.</exception> /// <exception cref="XmlReadException">if there is a problem reading the XML.</exception> /// <returns><see cref="SignedInfo"/></returns> public virtual SignedInfo ReadSignedInfo(XmlReader reader) { XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.SignedInfo, XmlSignatureConstants.Namespace); try { var defaultNamespace = reader.LookupNamespace(string.Empty); var bufferedStream = new MemoryStream(); var settings = new XmlWriterSettings { Encoding = Encoding.UTF8, NewLineHandling = NewLineHandling.None }; // need to read into buffer since the canonicalization reader needs a stream. using (XmlWriter bufferWriter = XmlDictionaryWriter.Create(bufferedStream, settings)) { bufferWriter.WriteNode(reader, true); bufferWriter.Flush(); } bufferedStream.Position = 0; // // We are creating a XmlDictionaryReader with a hard-coded Max XmlDictionaryReaderQuotas. This is a reader that we // are creating over an already buffered content. The content was initially read off user provided XmlDictionaryReader // with the correct quotas and hence we know the data is valid. // using (var canonicalizingReader = XmlDictionaryReader.CreateTextReader(bufferedStream, XmlDictionaryReaderQuotas.Max)) { var signedInfo = new SignedInfo(); signedInfo.CanonicalStream = new MemoryStream(); // TODO - should not always use 'false' canonicalizingReader.StartCanonicalization(signedInfo.CanonicalStream, false, null); canonicalizingReader.MoveToStartElement(XmlSignatureConstants.Elements.SignedInfo, XmlSignatureConstants.Namespace); signedInfo.Prefix = canonicalizingReader.Prefix; signedInfo.Id = canonicalizingReader.GetAttribute(XmlSignatureConstants.Attributes.Id, null); // read <SignedInfo ...> start element canonicalizingReader.Read(); // TODO - if comments are not false, then we need to reset. // this should be very rare. signedInfo.CanonicalizationMethod = ReadCanonicalizationMethod(canonicalizingReader); signedInfo.SignatureMethod = ReadSignatureMethod(canonicalizingReader); signedInfo.References.Add(ReadReference(canonicalizingReader)); if (canonicalizingReader.IsStartElement(XmlSignatureConstants.Elements.Reference, XmlSignatureConstants.Namespace)) { throw XmlUtil.LogReadException(LogMessages.IDX30020); } canonicalizingReader.ReadEndElement(); canonicalizingReader.EndCanonicalization(); signedInfo.CanonicalStream.Flush(); return(signedInfo); } } catch (Exception ex) { if (ex is XmlReadException) { throw; } throw XmlUtil.LogReadException(LogMessages.IDX30016, ex, XmlSignatureConstants.Elements.SignedInfo); } }
/// <summary> /// Writes the contents of a <see cref="SignedInfo"/> as XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-SignedInfo. /// </summary> /// <param name="writer">the <see cref="XmlWriter"/> to use.</param> /// <param name="signedInfo">the <see cref="SignedInfo"/>to write.</param> /// <remarks>Assumes the <Reference> digest has been calculated, no canonicalization or digest calculation is performed.</remarks> /// <exception cref="ArgumentNullException">if <paramref name="writer"/> is null.</exception> /// <exception cref="ArgumentNullException">if <paramref name="signedInfo"/> is null.</exception> /// <exception cref="XmlWriteException">if <see cref="SignedInfo.CanonicalizationMethod"/> is null or empty.</exception> /// <exception cref="XmlWriteException">if <see cref="SignedInfo.References"/> is null.</exception> /// <exception cref="NotSupportedException">if <see cref="SignedInfo.References" />.Count > 1.</exception> /// <exception cref="XmlWriteException">if <see cref="SignedInfo.SignatureMethod"/> is null or empty.</exception> public virtual void WriteSignedInfo(XmlWriter writer, SignedInfo signedInfo) { if (writer == null) { throw LogArgumentNullException(nameof(writer)); } if (signedInfo == null) { throw LogArgumentNullException(nameof(signedInfo)); } if (string.IsNullOrEmpty(signedInfo.CanonicalizationMethod)) { throw XmlUtil.LogWriteException(LogMessages.IDX30401, XmlSignatureConstants.Elements.SignedInfo, XmlSignatureConstants.Elements.CanonicalizationMethod); } if (string.IsNullOrEmpty(signedInfo.SignatureMethod)) { throw XmlUtil.LogWriteException(LogMessages.IDX30401, XmlSignatureConstants.Elements.SignedInfo, XmlSignatureConstants.Elements.SignatureMethod); } if (signedInfo.References == null) { throw XmlUtil.LogWriteException(LogMessages.IDX30405); } // <SignedInfo> writer.WriteStartElement(Prefix, XmlSignatureConstants.Elements.SignedInfo, XmlSignatureConstants.Namespace); // @Id if (signedInfo.Id != null) { writer.WriteAttributeString(XmlSignatureConstants.Attributes.Id, null, signedInfo.Id); } // <CanonicalizationMethod> writer.WriteStartElement(Prefix, XmlSignatureConstants.Elements.CanonicalizationMethod, XmlSignatureConstants.Namespace); //@Algorithm writer.WriteAttributeString(XmlSignatureConstants.Attributes.Algorithm, null, signedInfo.CanonicalizationMethod); writer.WriteEndElement(); // <SignatureMethod> writer.WriteStartElement(Prefix, XmlSignatureConstants.Elements.SignatureMethod, XmlSignatureConstants.Namespace); // @Algorithm writer.WriteAttributeString(XmlSignatureConstants.Attributes.Algorithm, null, signedInfo.SignatureMethod); // </SignatureMethod> writer.WriteEndElement(); // <Reference> foreach (var reference in signedInfo.References) { WriteReference(writer, reference); } // </SignedInfo> writer.WriteEndElement(); }
/// <summary> /// Initializes a <see cref="Signature"/> instance. /// </summary> /// <param name="signedInfo">associated with this Signature.</param> /// <exception cref="ArgumentNullException">if <paramref name="signedInfo"/> if null.</exception> public Signature(SignedInfo signedInfo) { SignedInfo = signedInfo; }