/// <summary> /// Reads XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-SignatureMethod /// </summary> /// <param name="reader">a <see cref="XmlReader"/>positioned on a <SignatureMethod> 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>A string with the signature method.</returns> public virtual string ReadSignatureMethod(XmlReader reader) { XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.SignatureMethod, XmlSignatureConstants.Namespace); try { bool isEmptyElement = reader.IsEmptyElement; var signatureMethod = reader.GetAttribute(XmlSignatureConstants.Attributes.Algorithm, null); if (signatureMethod == null) { throw XmlUtil.OnRequiredAttributeMissing(XmlSignatureConstants.Elements.SignatureMethod, XmlSignatureConstants.Attributes.Algorithm); } reader.Read(); reader.MoveToContent(); if (!isEmptyElement) { reader.MoveToContent(); reader.ReadEndElement(); } return(signatureMethod); } catch (Exception ex) { if (ex is XmlReadException) { throw; } throw XmlUtil.LogReadException(LogMessages.IDX30016, ex, XmlSignatureConstants.Elements.Transform); } }
/// <summary> /// Reads XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-Signature /// </summary> /// <param name="reader">a <see cref="XmlReader"/>positioned on a <Signature> 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="Signature"/></returns> public virtual Signature ReadSignature(XmlReader reader) { try { // <Signature> XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.Signature, XmlSignatureConstants.Namespace); var prefix = reader.Prefix; var id = reader.GetAttribute(XmlSignatureConstants.Attributes.Id, null); reader.Read(); var signedInfo = ReadSignedInfo(reader); reader.MoveToContent(); var signatureValue = reader.ReadElementContentAsString().Trim(); KeyInfo keyInfo = null; if (reader.IsStartElement(XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace)) { keyInfo = ReadKeyInfo(reader); } // </Signature> reader.MoveToContent(); // throw if we are not on EndElement, something unexpected if (reader.NodeType != XmlNodeType.EndElement) { throw XmlUtil.LogReadException(LogMessages.IDX30025, XmlSignatureConstants.Elements.Signature, reader.NodeType, reader.LocalName); } reader.ReadEndElement(); return(new Signature { Id = id, KeyInfo = keyInfo, Prefix = prefix, SignedInfo = signedInfo, SignatureValue = signatureValue }); } catch (Exception ex) { if (ex is XmlReadException) { throw; } throw XmlUtil.LogReadException(LogMessages.IDX30016, ex, XmlSignatureConstants.Elements.Signature); } }
/// <summary> /// Reads XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-CanonicalizationMethod /// </summary> /// <param name="reader">a <see cref="XmlReader"/>positioned on a <CanonicalizationMethod> 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>A string with the canonicalization method.</returns> public virtual string ReadCanonicalizationMethod(XmlReader reader) { // <CanonicalizationMethod> XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.CanonicalizationMethod, XmlSignatureConstants.Namespace); try { bool isEmptyElement = reader.IsEmptyElement; var algorithm = reader.GetAttribute(XmlSignatureConstants.Attributes.Algorithm, null); if (string.IsNullOrEmpty(algorithm)) { throw XmlUtil.LogReadException(LogMessages.IDX30013, XmlSignatureConstants.Elements.Signature, XmlSignatureConstants.Attributes.Algorithm); } if (algorithm != SecurityAlgorithms.ExclusiveC14nWithComments && algorithm != SecurityAlgorithms.ExclusiveC14n) { throw XmlUtil.LogReadException(LogMessages.IDX30100, XmlSignatureConstants.Elements.Transform, algorithm, SecurityAlgorithms.ExclusiveC14n, SecurityAlgorithms.ExclusiveC14nWithComments); } reader.Read(); reader.MoveToContent(); if (!isEmptyElement) { if (reader.IsStartElement(XmlSignatureConstants.ExclusiveC14nInclusiveNamespaces)) { throw XmlUtil.LogReadException(LogMessages.IDX30107); } reader.MoveToContent(); reader.ReadEndElement(); } return(algorithm); } catch (Exception ex) { if (ex is XmlReadException) { throw; } throw XmlUtil.LogReadException(LogMessages.IDX30016, ex, XmlSignatureConstants.Elements.Transform); } }
/// <summary> /// Reads XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-KeyInfo /// </summary> /// <param name="reader"><see cref="XmlReader"/> pointing positioned on a <KeyInfo> element.</param> /// <exception cref="ArgumentNullException">if <paramref name="reader"/> is null.</exception> /// <exception cref="XmlReadException">if there is a problem reading the XML.</exception> /// <remarks>Only handles IssuerSerial, Ski, SubjectName, Certificate. Unsupported types are skipped. Only a X509 data element is supported.</remarks> public virtual KeyInfo ReadKeyInfo(XmlReader reader) { XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace); var keyInfo = new KeyInfo { Prefix = reader.Prefix }; try { bool isEmptyElement = reader.IsEmptyElement; // <KeyInfo> reader.ReadStartElement(); while (reader.IsStartElement()) { // <X509Data> if (reader.IsStartElement(XmlSignatureConstants.Elements.X509Data, XmlSignatureConstants.Namespace)) { keyInfo.X509Data.Add(ReadX509Data(reader)); } // <RetrievalMethod> else if (reader.IsStartElement(XmlSignatureConstants.Elements.RetrievalMethod, XmlSignatureConstants.Namespace)) { keyInfo.RetrievalMethodUri = reader.GetAttribute(XmlSignatureConstants.Attributes.URI); reader.ReadOuterXml(); } // <KeyName> else if (reader.IsStartElement(XmlSignatureConstants.Elements.KeyName, XmlSignatureConstants.Namespace)) { keyInfo.KeyName = reader.ReadElementContentAsString(XmlSignatureConstants.Elements.KeyName, XmlSignatureConstants.Namespace); } // <KeyValue> else if (reader.IsStartElement(XmlSignatureConstants.Elements.KeyValue, XmlSignatureConstants.Namespace)) { reader.ReadStartElement(XmlSignatureConstants.Elements.KeyValue, XmlSignatureConstants.Namespace); if (reader.IsStartElement(XmlSignatureConstants.Elements.RSAKeyValue, XmlSignatureConstants.Namespace)) { // Multiple RSAKeyValues were found if (keyInfo.RSAKeyValue != null) { throw XmlUtil.LogReadException(LogMessages.IDX30015, XmlSignatureConstants.Elements.RSAKeyValue); } keyInfo.RSAKeyValue = ReadRSAKeyValue(reader); } else { // Skip the element since it is not an <RSAKeyValue> LogHelper.LogWarning(LogMessages.IDX30300, reader.ReadOuterXml()); } // </KeyValue> reader.ReadEndElement(); } else { // Skip the element since it is not one of <RetrievalMethod>, <X509Data>, <KeyValue> LogHelper.LogWarning(LogMessages.IDX30300, reader.ReadOuterXml()); } } // </KeyInfo> if (!isEmptyElement) { reader.ReadEndElement(); } } catch (Exception ex) { if (ex is XmlReadException) { throw; } throw XmlUtil.LogReadException(LogMessages.IDX30017, ex, XmlSignatureConstants.Elements.KeyInfo, ex); } return(keyInfo); }
/// <summary> /// Reads XML conforming to https://www.w3.org/TR/2001/PR-xmldsig-core-20010820/#sec-Reference /// </summary> /// <param name="reader">a <see cref="XmlReader"/>positioned on a <Reference> 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="Reference"/></returns> public virtual Reference ReadReference(XmlReader reader) { XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.Reference, XmlSignatureConstants.Namespace); try { var reference = new Reference { Prefix = reader.Prefix, Id = reader.GetAttribute(XmlSignatureConstants.Attributes.Id, null), Type = reader.GetAttribute(XmlSignatureConstants.Attributes.Type, null), Uri = reader.GetAttribute(XmlSignatureConstants.Attributes.URI, null) }; reader.Read(); ReadTransforms(reader, reference); // <DigestMethod> - required XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.DigestMethod, XmlSignatureConstants.Namespace); bool isEmptyElement = reader.IsEmptyElement; var digestMethod = reader.GetAttribute(XmlSignatureConstants.Attributes.Algorithm, null); if (string.IsNullOrEmpty(digestMethod)) { throw XmlUtil.OnRequiredAttributeMissing(XmlSignatureConstants.Elements.DigestMethod, XmlSignatureConstants.Attributes.Algorithm); } reference.DigestMethod = digestMethod; reader.Read(); reader.MoveToContent(); if (!isEmptyElement) { reader.ReadEndElement(); } // <DigestValue> XmlUtil.CheckReaderOnEntry(reader, XmlSignatureConstants.Elements.DigestValue, XmlSignatureConstants.Namespace); var digestValue = reader.ReadElementContentAsString().Trim(); if (string.IsNullOrEmpty(digestValue)) { throw XmlUtil.LogReadException(LogMessages.IDX30206, reference.Uri ?? reference.Id); } reference.DigestValue = digestValue; // </Reference> reader.MoveToContent(); reader.ReadEndElement(); return(reference); } catch (Exception ex) { if (ex is XmlReadException) { throw; } throw XmlUtil.LogReadException(LogMessages.IDX30016, ex, XmlSignatureConstants.Elements.Reference); } }
/// <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); } }