如何在 C# 中使用证书文件验证签名值?
How to verify Signature Value using cert file in C#?
我是安全新手,对此深表歉意。我有一个 xml 文件,其中包括
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ID_VG_Response>
<Result>
<SubjectDN>CN="XX", SERIALNUMBER=XX/XX, C=IN</SubjectDN>
<UserIDN>XX</UserIDN>
<CardNumber>XX</CardNumber>
<TransactionType>XX</TransactionType>
<Status>Success</Status>
</Result>
<Validity>180</Validity>
<SignatureTime>
<date>20150726</date>
<time>15:01:51:927</time>
</SignatureTime>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>XXX</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>XXXXXXXXXX</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>XXXX</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</ID_VG_Response>
和一些cer文件。现在我需要使用 C# 中的 cer 文件验证 SignatureValue。谁能帮帮我吗?一位同事向我发送了一个 java 文件来验证这一点,但我需要在 C# 中执行此操作?这是java代码,
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import sun.misc.BASE64Decoder;
import sun.security.x509.X509CertImpl;
public class XMLSignatureValidator {
private String userIDN;
public static void main(String[] args) throws Exception {
XMLSignatureValidator validator = new XMLSignatureValidator();
//boolean verified = validator.verifyVGResponse(new FileInputStream(
// "C:/ID_VG_Response.xml"), "CA");
FileInputStream fis = new FileInputStream("C:/ID_VG_Response.xml");
byte[] data = new byte[fis.available()];
fis.read(data);
fis.close();
boolean verified = validator.verifyVGResponse(new String(data),
"E:/EIDA Toolkit/VG Related/ADSIC_Prod/VG Response Cert");
System.out.println(verified);
}
public boolean verifyVGResponse(final String vgResponse,
final String cAFolderPath) throws Exception {
byte[] xml = new BASE64Decoder().decodeBuffer(vgResponse);
return verifyVGResponse(new ByteArrayInputStream(xml), cAFolderPath);
}
public boolean verifyVGResponse(final InputStream vgResponse,
final String cAFolderPath) throws Exception {
X509Certificate[] certificates = getCertificates(cAFolderPath);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(vgResponse);
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS,
"Signature");
if (nl.getLength() == 0) {
throw new Exception("Cannot find Signature element");
}
final X509KeySelector keySelector = new X509KeySelector();
DOMValidateContext valContext = new DOMValidateContext(keySelector,
nl.item(0));
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM",
new org.jcp.xml.dsig.internal.dom.XMLDSigRI());
final XMLSignature signature = factory
.unmarshalXMLSignature(valContext);
// Verify signature.
boolean coreValidity = signature.validate(valContext);
if (coreValidity) {
// Verify the complete certificate chain.
final X509CertImpl signerCertImpl = (X509CertImpl) keySelector
.getSignerCertificate();
final X509Certificate signerCert = javax.security.cert.X509Certificate
.getInstance(signerCertImpl.getEncoded());
boolean verified = verifyCertificate(signerCert, certificates);
if (verified) {
NodeList nl2 = doc.getElementsByTagName("Status");
if (!nl2.item(0).getFirstChild().getNodeValue()
.equalsIgnoreCase("Success")) {
throw new Exception("Status element not set to success");
}
long signerTime = new SimpleDateFormat("yyyyMMdd HH:mm:ss:SSS")
.parse(doc.getElementsByTagName("date").item(0)
.getFirstChild().getNodeValue()
+ " "
+ doc.getElementsByTagName("time").item(0)
.getFirstChild().getNodeValue())
.getTime();
int validitySec = Integer.parseInt(doc
.getElementsByTagName("Validity").item(0)
.getFirstChild().getNodeValue());
System.out.println("signer time: " + signerTime);
System.out.println("signer time date: " + new Date(signerTime));
System.out.println("validitySec: " + validitySec);
System.out.println("validitySec * 1000: " + validitySec * 1000);
Date d = new Date();
System.out.println("Date on the server is: " + d);
System.out.println("Date on server in milliseconds: " + d.getTime());
System.out.println(d.getTime() > signerTime + validitySec * 1000);
if (d.getTime() > signerTime + validitySec * 1000) {
throw new Exception("VG response expired");
}
userIDN = doc.getElementsByTagName("UserIDN").item(0)
.getFirstChild().getNodeValue();
return true;
} else {
throw new Exception("Certificate Not Valid");
}
}
throw new Exception("Signature Not Valid");
}
// CHECKSTYLE_IGNORE_START
private final boolean verifyCertificate(final X509Certificate signerCert,
final X509Certificate[] certificates) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchProviderException,
SignatureException, CertificateException {
// CHECKSTYLE_IGNORE_END
signerCert.checkValidity();
X509Certificate issuerCert = null;
String issuerDN = signerCert.getIssuerDN().getName();
for (int i = 0; i < certificates.length; i++) {
if (certificates[i].getSubjectDN().getName().equals(issuerDN)) {
issuerCert = certificates[i];
break;
}
}
if (issuerCert == null) {
return false;
}
signerCert.verify(issuerCert.getPublicKey());
for (int i = 0; i < certificates.length; i++) {
if (signerCert.getSerialNumber().equals(
certificates[i].getSerialNumber())) {
return true;
}
}
return false;
}
// CHECKSTYLE_IGNORE_START
private class SimpleKeySelectorResult implements KeySelectorResult {
Key pk = null;
SimpleKeySelectorResult(Key _pk) {
pk = _pk;
}
// @Override
public Key getKey() {
return pk;
}
}
// CHECKSTYLE_IGNORE_END
public class X509KeySelector extends KeySelector {
private X509CertImpl cert;
@SuppressWarnings("rawtypes")
public KeySelectorResult select(KeyInfo keyInfo,
KeySelector.Purpose purpose, AlgorithmMethod method,
XMLCryptoContext context) throws KeySelectorException {
Iterator ki = keyInfo.getContent().iterator();
while (ki.hasNext()) {
XMLStructure info = (XMLStructure) ki.next();
if (!(info instanceof X509Data)) {
continue;
}
X509Data x509Data = (X509Data) info;
Iterator xi = x509Data.getContent().iterator();
while (xi.hasNext()) {
Object o = xi.next();
if (o instanceof X509Certificate) {
// Currently not used, the object returned is
// X509CertImpl
PublicKey key = ((X509Certificate) o).getPublicKey();
// Make sure the algorithm is compatible
// with the method.
if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
return new SimpleKeySelectorResult(key);
}
}
if (o instanceof X509CertImpl) {
cert = ((X509CertImpl) o);
PublicKey key = ((X509CertImpl) o).getPublicKey();
// Make sure the algorithm is compatible
// with the method.
if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
return new SimpleKeySelectorResult(key);
}
}
}
}
throw new KeySelectorException("No key found!");
}
public X509CertImpl getSignerCertificate() {
return cert;
}
// CHECKSTYLE_IGNORE_START
boolean algEquals(String algURI, String algName) {
if (algName.equalsIgnoreCase("DSA")
&& algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {
return true;
} else if (algName.equalsIgnoreCase("RSA")
&& algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {
return true;
} else if (algName.equalsIgnoreCase("RSA")
&& algURI
.equalsIgnoreCase("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")) {
return true;
} else {
return false;
}
}
// CHECKSTYLE_IGNORE_END
}
private static X509Certificate[] getCertificates(String cAFolderPath)
throws FileNotFoundException, CertificateException {
ArrayList<X509Certificate> certificates = new ArrayList<X509Certificate>();
File f = new File(cAFolderPath);
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
X509Certificate cert = X509Certificate
.getInstance(new FileInputStream(files[i]));
certificates.add(cert);
}
X509Certificate[] certs = new X509Certificate[certificates.size()];
if (certificates.size() != 0) {
for (int i = 0; i < certs.length; i++) {
certs[i] = certificates.get(i);
}
return certs;
}
}
return null;
}
public String getUserIDN() {
return userIDN;
}
public void setUserIDN(String userIDN) {
this.userIDN = userIDN;
}
}
如果您有 public 键(类似于):
<RSAKeyValue>
<Modulus>tt5QV .... kJqsMZ2yuxZfoyQ==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
您应该能够验证已签名的 xml 文档,例如:
private bool TryGetValidDocument(string publicKey, XmlDocument doc)
{
var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(publicKey);
var nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("sig", "http://www.w3.org/2000/09/xmldsig#");
var signedXml = new SignedXml(doc);
var sig = (XmlElement) doc.SelectSingleNode("//sig:Signature", nsMgr);
if (sig == null)
{
Console.WriteLine("Could not find the signature node");
return false;
}
signedXml.LoadXml(sig);
return signedXml.CheckSignature(rsa);
}
有关更多信息,请关注此 link
对于证书非常相似。代码应如下所示:
private bool TryGetValidDocument(X509Certificate2 cert, XmlDocument doc)
{
var nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("sig", "http://www.w3.org/2000/09/xmldsig#");
var signedXml = new SignedXml(doc);
var sig = (XmlElement) doc.SelectSingleNode("//sig:Signature", nsMgr);
if (sig == null)
{
Logger.Warn("Could not find the signature node");
return false;
}
signedXml.LoadXml(sig);
return signedXml.CheckSignature(cert, true);
}
可以找到完整的示例here
我是安全新手,对此深表歉意。我有一个 xml 文件,其中包括
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ID_VG_Response>
<Result>
<SubjectDN>CN="XX", SERIALNUMBER=XX/XX, C=IN</SubjectDN>
<UserIDN>XX</UserIDN>
<CardNumber>XX</CardNumber>
<TransactionType>XX</TransactionType>
<Status>Success</Status>
</Result>
<Validity>180</Validity>
<SignatureTime>
<date>20150726</date>
<time>15:01:51:927</time>
</SignatureTime>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<DigestValue>XXX</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>XXXXXXXXXX</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>XXXX</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</ID_VG_Response>
和一些cer文件。现在我需要使用 C# 中的 cer 文件验证 SignatureValue。谁能帮帮我吗?一位同事向我发送了一个 java 文件来验证这一点,但我需要在 C# 中执行此操作?这是java代码,
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import sun.misc.BASE64Decoder;
import sun.security.x509.X509CertImpl;
public class XMLSignatureValidator {
private String userIDN;
public static void main(String[] args) throws Exception {
XMLSignatureValidator validator = new XMLSignatureValidator();
//boolean verified = validator.verifyVGResponse(new FileInputStream(
// "C:/ID_VG_Response.xml"), "CA");
FileInputStream fis = new FileInputStream("C:/ID_VG_Response.xml");
byte[] data = new byte[fis.available()];
fis.read(data);
fis.close();
boolean verified = validator.verifyVGResponse(new String(data),
"E:/EIDA Toolkit/VG Related/ADSIC_Prod/VG Response Cert");
System.out.println(verified);
}
public boolean verifyVGResponse(final String vgResponse,
final String cAFolderPath) throws Exception {
byte[] xml = new BASE64Decoder().decodeBuffer(vgResponse);
return verifyVGResponse(new ByteArrayInputStream(xml), cAFolderPath);
}
public boolean verifyVGResponse(final InputStream vgResponse,
final String cAFolderPath) throws Exception {
X509Certificate[] certificates = getCertificates(cAFolderPath);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(vgResponse);
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS,
"Signature");
if (nl.getLength() == 0) {
throw new Exception("Cannot find Signature element");
}
final X509KeySelector keySelector = new X509KeySelector();
DOMValidateContext valContext = new DOMValidateContext(keySelector,
nl.item(0));
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM",
new org.jcp.xml.dsig.internal.dom.XMLDSigRI());
final XMLSignature signature = factory
.unmarshalXMLSignature(valContext);
// Verify signature.
boolean coreValidity = signature.validate(valContext);
if (coreValidity) {
// Verify the complete certificate chain.
final X509CertImpl signerCertImpl = (X509CertImpl) keySelector
.getSignerCertificate();
final X509Certificate signerCert = javax.security.cert.X509Certificate
.getInstance(signerCertImpl.getEncoded());
boolean verified = verifyCertificate(signerCert, certificates);
if (verified) {
NodeList nl2 = doc.getElementsByTagName("Status");
if (!nl2.item(0).getFirstChild().getNodeValue()
.equalsIgnoreCase("Success")) {
throw new Exception("Status element not set to success");
}
long signerTime = new SimpleDateFormat("yyyyMMdd HH:mm:ss:SSS")
.parse(doc.getElementsByTagName("date").item(0)
.getFirstChild().getNodeValue()
+ " "
+ doc.getElementsByTagName("time").item(0)
.getFirstChild().getNodeValue())
.getTime();
int validitySec = Integer.parseInt(doc
.getElementsByTagName("Validity").item(0)
.getFirstChild().getNodeValue());
System.out.println("signer time: " + signerTime);
System.out.println("signer time date: " + new Date(signerTime));
System.out.println("validitySec: " + validitySec);
System.out.println("validitySec * 1000: " + validitySec * 1000);
Date d = new Date();
System.out.println("Date on the server is: " + d);
System.out.println("Date on server in milliseconds: " + d.getTime());
System.out.println(d.getTime() > signerTime + validitySec * 1000);
if (d.getTime() > signerTime + validitySec * 1000) {
throw new Exception("VG response expired");
}
userIDN = doc.getElementsByTagName("UserIDN").item(0)
.getFirstChild().getNodeValue();
return true;
} else {
throw new Exception("Certificate Not Valid");
}
}
throw new Exception("Signature Not Valid");
}
// CHECKSTYLE_IGNORE_START
private final boolean verifyCertificate(final X509Certificate signerCert,
final X509Certificate[] certificates) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchProviderException,
SignatureException, CertificateException {
// CHECKSTYLE_IGNORE_END
signerCert.checkValidity();
X509Certificate issuerCert = null;
String issuerDN = signerCert.getIssuerDN().getName();
for (int i = 0; i < certificates.length; i++) {
if (certificates[i].getSubjectDN().getName().equals(issuerDN)) {
issuerCert = certificates[i];
break;
}
}
if (issuerCert == null) {
return false;
}
signerCert.verify(issuerCert.getPublicKey());
for (int i = 0; i < certificates.length; i++) {
if (signerCert.getSerialNumber().equals(
certificates[i].getSerialNumber())) {
return true;
}
}
return false;
}
// CHECKSTYLE_IGNORE_START
private class SimpleKeySelectorResult implements KeySelectorResult {
Key pk = null;
SimpleKeySelectorResult(Key _pk) {
pk = _pk;
}
// @Override
public Key getKey() {
return pk;
}
}
// CHECKSTYLE_IGNORE_END
public class X509KeySelector extends KeySelector {
private X509CertImpl cert;
@SuppressWarnings("rawtypes")
public KeySelectorResult select(KeyInfo keyInfo,
KeySelector.Purpose purpose, AlgorithmMethod method,
XMLCryptoContext context) throws KeySelectorException {
Iterator ki = keyInfo.getContent().iterator();
while (ki.hasNext()) {
XMLStructure info = (XMLStructure) ki.next();
if (!(info instanceof X509Data)) {
continue;
}
X509Data x509Data = (X509Data) info;
Iterator xi = x509Data.getContent().iterator();
while (xi.hasNext()) {
Object o = xi.next();
if (o instanceof X509Certificate) {
// Currently not used, the object returned is
// X509CertImpl
PublicKey key = ((X509Certificate) o).getPublicKey();
// Make sure the algorithm is compatible
// with the method.
if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
return new SimpleKeySelectorResult(key);
}
}
if (o instanceof X509CertImpl) {
cert = ((X509CertImpl) o);
PublicKey key = ((X509CertImpl) o).getPublicKey();
// Make sure the algorithm is compatible
// with the method.
if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
return new SimpleKeySelectorResult(key);
}
}
}
}
throw new KeySelectorException("No key found!");
}
public X509CertImpl getSignerCertificate() {
return cert;
}
// CHECKSTYLE_IGNORE_START
boolean algEquals(String algURI, String algName) {
if (algName.equalsIgnoreCase("DSA")
&& algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) {
return true;
} else if (algName.equalsIgnoreCase("RSA")
&& algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) {
return true;
} else if (algName.equalsIgnoreCase("RSA")
&& algURI
.equalsIgnoreCase("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")) {
return true;
} else {
return false;
}
}
// CHECKSTYLE_IGNORE_END
}
private static X509Certificate[] getCertificates(String cAFolderPath)
throws FileNotFoundException, CertificateException {
ArrayList<X509Certificate> certificates = new ArrayList<X509Certificate>();
File f = new File(cAFolderPath);
if (f.isDirectory()) {
File[] files = f.listFiles();
for (int i = 0; i < files.length; i++) {
X509Certificate cert = X509Certificate
.getInstance(new FileInputStream(files[i]));
certificates.add(cert);
}
X509Certificate[] certs = new X509Certificate[certificates.size()];
if (certificates.size() != 0) {
for (int i = 0; i < certs.length; i++) {
certs[i] = certificates.get(i);
}
return certs;
}
}
return null;
}
public String getUserIDN() {
return userIDN;
}
public void setUserIDN(String userIDN) {
this.userIDN = userIDN;
}
}
如果您有 public 键(类似于):
<RSAKeyValue>
<Modulus>tt5QV .... kJqsMZ2yuxZfoyQ==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
您应该能够验证已签名的 xml 文档,例如:
private bool TryGetValidDocument(string publicKey, XmlDocument doc)
{
var rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(publicKey);
var nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("sig", "http://www.w3.org/2000/09/xmldsig#");
var signedXml = new SignedXml(doc);
var sig = (XmlElement) doc.SelectSingleNode("//sig:Signature", nsMgr);
if (sig == null)
{
Console.WriteLine("Could not find the signature node");
return false;
}
signedXml.LoadXml(sig);
return signedXml.CheckSignature(rsa);
}
有关更多信息,请关注此 link
对于证书非常相似。代码应如下所示:
private bool TryGetValidDocument(X509Certificate2 cert, XmlDocument doc)
{
var nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("sig", "http://www.w3.org/2000/09/xmldsig#");
var signedXml = new SignedXml(doc);
var sig = (XmlElement) doc.SelectSingleNode("//sig:Signature", nsMgr);
if (sig == null)
{
Logger.Warn("Could not find the signature node");
return false;
}
signedXml.LoadXml(sig);
return signedXml.CheckSignature(cert, true);
}
可以找到完整的示例here