Hey Friends,
i am trying to verify the signature of our partner using x509 certificate
public.
i am able to retrieve the certificate from store but when i call the
CheckSignature method on the signedxml object then i get the following
unhandled exception.
"pCertContext is an invalid handle."
The Code that creates the exception is this
where SignedXML is a signedxml object.FoundCert is the public Certificate i
am retrieving from my store.
if (SignedXML.CheckSignature(FoundCert, false))
{
// Signature verified.
return true;
}
The Following is the Full Code i am using:
//Get CertificateMethod
public X509Certificate2 GetX509Certificate(string IssuerName, string
SerialNumber,int i)
{
X509Certificate2 FoundCert = null;
X509Store store = null;
if (i==0)
{
store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
}
else
{
store = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine);
}
store.Open(OpenFlags.ReadOnly);
X509CertificateCollection certs = store.Certificates;
// Search the certificates to find matching issuer name and serial number
foreach (X509Certificate2 cert in certs)
{
string aszcertserial=GetSerialNumber(cert.GetSerialNumber());
if ((IssuerName == cert.Issuer)
&& (SerialNumber == GetSerialNumber(cert.GetSerialNumber())))
{
// Find the match. Exit the loop.
FoundCert = cert;
break;
}
}
store.Close();
return FoundCert;
}
//VerifySignature method
public bool VerifySignature( )
{
XmlDocument aobDocument = new XmlDocument();
aobDocument.Load(System.Web.HttpContext.Current.Server.MapPath("ReadSample/R1_Signed_Sample.xml"));
XmlNodeList nodeList = aobDocument.GetElementsByTagName("X509IssuerName",
"http://www.w3.org/2000/09/xmldsig#");
XmlElement issuerNameElement = ((XmlElement)(nodeList[0]));
string issuerName = issuerNameElement.InnerText;
nodeList = aobDocument.GetElementsByTagName("X509SerialNumber",
"http://www.w3.org/2000/09/xmldsig#");
XmlElement serialNumberElement = (XmlElement)(nodeList[0]);
String serialNumber = serialNumberElement.InnerText;
// Dim MSCert As Microsoft.Web.Services.Security.X509.X509Certificate
X509Certificate2 FoundCert = GetX509Certificate(issuerName, serialNumber,1);
return VerifySignature(FoundCert);
}
public bool VerifySignature(X509Certificate2 FoundCert)
{
Microsoft.Web.Services3.SoapEnvelope aobDocument = new
Microsoft.Web.Services3.SoapEnvelope();
//XmlDocument aobDocument = new XmlDocument();
aobDocument.PreserveWhitespace = true;
aobDocument.Load(System.Web.HttpContext.Current.Server.MapPath("ReadSample/R1_Signed_Sample.xml"));
SignedXML SignedXML = new SignedXML((XmlDocument)(aobDocument));
XmlNodeList nodeList = aobDocument.GetElementsByTagName("Signature",
"http://www.w3.org/2000/09/xmldsig#");
SignedXML.LoadXml((XmlElement)(nodeList[0]));
try
{
if (SignedXML.CheckSignature(FoundCert, false))
{
// Signature verified.
return true;
}
else
{
//Signature verification failed.
return false;
}
}
catch (Exception ex)
{
throw;
}
}
private string GetSerialNumber(byte[] SerialNumber)
{
long[] outputDigits=new long[39];
int currentByte;
for (currentByte = SerialNumber.GetUpperBound(0); (currentByte >= 1);
currentByte = (currentByte-1))
{
outputDigits[38] = (outputDigits[38] +
(Convert.ToInt64(SerialNumber[currentByte])));
flattenDigits(ref outputDigits, 256);
}
outputDigits[38] = (outputDigits[38] + ((long)(SerialNumber[0])));
flattenDigits(ref outputDigits);
return digitsToString(outputDigits);
}
private void flattenDigits(ref long[] bumpyDigits)
{
flattenDigits(ref bumpyDigits, 1);
}
private void flattenDigits(ref long[] bumpyDigits, int multiplier)
{
long nextValueAddition = 0;
for (int currentDigit = bumpyDigits.GetUpperBound(0); (currentDigit >= 0);
currentDigit = (currentDigit-1))
{
bumpyDigits[currentDigit] =
bumpyDigits[currentDigit]*Convert.ToInt64(multiplier);
bumpyDigits[currentDigit] = (bumpyDigits[currentDigit] + nextValueAddition);
nextValueAddition = bumpyDigits[currentDigit]/10;
bumpyDigits[currentDigit] = (bumpyDigits[currentDigit] % 10);
}
}
private string digitsToString(long[] digits)
{
int currentDigit = 0;
StringBuilder outputString = new StringBuilder();
while (((digits[currentDigit] == 0)
&& currentDigit != 38))
{
currentDigit++;
}
do
{
outputString.Append(digits[currentDigit].ToString());
currentDigit++;
}
while (currentDigit < 39);
return outputString.ToString();
}
The Following is the Xml
<?xml version="1.0" encoding="UTF-8" ?>
- <B:Envelope xmlns:B="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:A="http://www.routeone.com/namespace.messaging.diag#"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <SOAP:Header
xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"
xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
- <SOAP-SEC:Signature SOAP:mustUnderstand="1">
- <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"
xmlns:C="http://www.routeone.com/namespace.messaging.CreditApplication#"
xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
- <SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
- <Reference URI="#Body">
- <Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>niQfM6RR1CP+V1Puf9FlaXRNcFQ=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Ii68Od4N0zOe+UwJyBDe1aQlC1YbteOk4YNjyOal9m6f7KbO4SqPdaX4CJZIIt1Z5f7iOgzhK6nuCi08RPyqXPvdeuivNNOq6/4a7iJZxQD2PMAFBVAVwAuLmIRAh0u6MkzA/u0069JvP90mOpYtG1euXf5oSKI+XCmdSKIBjv5FNmg9XTaruy2cg3Iz+KOUInMPnG7AJcmJRnaLLr/5za6Bu1CgpeS0/aBVhf2xpF7/A9qa/sjiQR2dfwPM+InawXV94SD8HEd6QFzfE5WxrWLkVXOBeiCyNvYXX9CTcmPQFUnvVxA1+L9TMx4reb835ZT0Hi2aP2hu7PQiWAaFdw==</SignatureValue>
- <KeyInfo>
- <X509Data>
<X509Certificate />
- <X509IssuerSerial>
<X509IssuerName>OU=www.verisign.com/CPS Incorp.by Ref. LIABILITY LTD.(c)97
VeriSign, OU=VeriSign International Server CA - Class 3, OU="VeriSign,
Inc.", O=VeriSign Trust Network</X509IssuerName>
<X509SerialNumber>160283950701092051351433675048676869301</X509SerialNumber>
</X509IssuerSerial>
</X509Data>
</KeyInfo>
</Signature>
</SOAP-SEC:Signature>
</SOAP:Header>
- <B:Body id="Body"
xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"
xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
- <A:Diagnostic>
- <A:DiagnosticMessage>
<A:RequestMessage>100027</A:RequestMessage>
</A:DiagnosticMessage>
<A:SourceIdentifier>RouteOne</A:SourceIdentifier>
</A:Diagnostic>
</B:Body>
</B:Envelope>
The Full Description of the Error is
System.Security.Cryptography.CryptographicException was unhandled by user
code
Message="pCertContext is an invalid handle."
Source="System"
StackTrace:
at
System.Security.Cryptography.CAPI.CertAddCertificateLinkToStore(SafeCertStoreHandle
hCertStore, SafeCertContextHandle pCertContext, UInt32 dwAddDisposition,
SafeCertContextHandle ppStoreContext)
at
System.Security.Cryptography.X509Certificates.X509Utils.ExportToMemoryStore(X509Certificate2Collection
collection)
at
System.Security.Cryptography.X509Certificates.X509Chain.BuildChain(IntPtr
hChainEngine, SafeCertContextHandle pCertContext, X509Certificate2Collection
extraStore, OidCollection applicationPolicy, OidCollection
certificatePolicy, X509RevocationMode revocationMode, X509RevocationFlag
revocationFlag, DateTime verificationTime, TimeSpan timeout,
SafeCertChainHandle& ppChainContext)
at
System.Security.Cryptography.X509Certificates.X509Chain.Build(X509Certificate2
certificate)
at
System.Security.Cryptography.Xml.SignedXml.CheckSignature(X509Certificate2
certificate, Boolean verifySignatureOnly)
at Signer.VerifySignature(X509Certificate2 FoundCert) in
c:\Inetpub\wwwroot\TestMSMQ\MessageSigning.aspx.cs:line 201
at Signer.VerifySignature() in
c:\Inetpub\wwwroot\TestMSMQ\MessageSigning.aspx.cs:line 152
at MessageSigning.Page_Load(Object sender, EventArgs e) in
c:\Inetpub\wwwroot\TestMSMQ\MessageSigning.aspx.cs:line 65
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp,
Object o, Object t, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object
sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Steven Cheng[MSFT] - 05 Dec 2006 04:41 GMT
Hello Param,
I think the code of certificate retrieving should be ok. I suggest you
check the returned certificate value to see whether it is the one of your
expected certificate. Also, you can try using teh CertificateCollection
Find method to locate the certain certificate you want:
=====================
X509Store store = new X509Store(StoreName.AddressBook,
StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert =
store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName,
"CN=WSE2QuickStartServer",false)[0];
store.Close();
====================
Sincerely,
Steven Cheng
Microsoft MSDN Online Support Lead
This posting is provided "AS IS" with no warranties, and confers no rights.