Search code examples
xmlwcfweb-servicesdigital-signaturex509certificate2

X509Certificate2 validation on web service


I'm developing WCF web service that checks if a certificate in XML signature is valid. XML is signed with qualified and valid X509 certificate. While I am running service within Visual Studio development environment X509Certificate2.Verify() and X509Chain.Build() methods return TRUE. But when I publish my service under IIS these methods return FALSE. What I am doing wrong or what is missing? Here is my validation code:

    public static void VerifyXml(XmlDocument xDoc)
    {
        // Create a new SignedXml object and pass it
        // the XML document class.
        SignedXml signedXml = new SignedXml(xDoc);

        // Find the "Signature" node and create a new
        // XmlNodeList object.
        XmlNodeList nodeList = xDoc.GetElementsByTagName("Signature");

        // Load the first <signature> node.  
        signedXml.LoadXml((XmlElement)nodeList[0]);

        IEnumerable<KeyInfoX509Data> x509Data = signedXml.KeyInfo.Cast<KeyInfoX509Data>();
        KeyInfoX509Data info = x509Data.First<KeyInfoX509Data>();
        X509Certificate2 cert = info.Certificates[0] as X509Certificate2;

        bool certIsValid = cert.Verify();
        // Here I receive TRUE in development environment and FALSE under IIS
        if (!certIsValid)
            throw new X509Exception("Invalid certificate");

        bool chainIsValid = false;
        X509Chain chain = new X509Chain();
        chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
        chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
        chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
        chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
        chainIsValid = chain.Build(cert);
        // Here I also receive TRUE in development environment and FALSE under IIS
        if (!chainIsValid)
            throw new X509Exception("Chain is invalid");

        // Check the signature
        bool signatureOK = signedXml.CheckSignature(cert, false);
        if (!signatureOK)
            throw new X509Exception("Signature is invalid");
     }

Any ideas? Thanks


Solution

  • Where is the root certificate located? I think ASP.NET will use the local machine store -- perhaps VS development server uses the user store and is finding the root certificate there but ASP.NET is not finding it? Try adding the root certificate to the local machine store.

    You can check the statuses in the X509Chain to get more details:

    foreach (X509ChainElement element in chain.ChainElements)
    {
        Console.WriteLine ("Element issuer name: {0}", element.Certificate.Issuer);
        Console.WriteLine ("Element certificate valid until: {0}", element.Certificate.NotAfter);
        Console.WriteLine ("Element certificate is valid: {0}", element.Certificate.Verify ());
        Console.WriteLine ("Element error status length: {0}", element.ChainElementStatus.Length);
        Console.WriteLine ("Element information: {0}", element.Information);
        Console.WriteLine ("Number of element extensions: {0}{1}", element.Certificate.Extensions.Count, Environment.NewLine);
    
        if (ch.ChainStatus.Length > 1)
        {
            for (int index = 0; index < element.ChainElementStatus.Length; index++)
            {
                Console.WriteLine (element.ChainElementStatus[index].Status);
                Console.WriteLine (element.ChainElementStatus[index].StatusInformation);
            }
        }
    }