Using X509IncludeOption to avoid "System.Security.Cryptography.CryptographicException: A certificate chain could not be built to a trusted root authority"
In the System.Security.Cryptography.X509Certificates namespace, X509IncludeOption is an enumeration that is defined as:
public enum X509IncludeOption
msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509includeoption(v=vs.110).aspx has all the details regarding the above enumeration, but for clarity here is a brief summary.
The enum specifies the amount of the certificate chain that should be included in the X.509 data.
None - No chain information should be included.
ExcludeRoot - Except the root certificate the full chain is included.
EndCertOnly - This means the leaf certificate should be included in the X.509 data.
WholeChain - The entire chain from the root to the leaf.
At times while trying to compute a signature or verifying a certificate chain we get an exception saying: System.Security.Cryptography.CryptographicException: A certificate chain could not be built to a trusted root authority.
Ideally a CAPI2 trace can provide more information on why the certificate chain verification failed. If you are using the SignedCms class for computing signature then also the chain will be verified and can fail if the chain building fails.
A quick way to test the chain is to use X509Chain.Build method which builds an X.509 chain using the policy specified in X509ChainPolicy.
X509Chain ch = new X509Chain();
If the chain building fails and you would still like to use the existing certificate to get past the crypto exception then you can use the X509IncludeOption enumeration to exclude the chain, for example you can try using X509IncludeOption.EndCertOnly and see if that helps in getting past the crypto exception.
For example the code below shows the usage of SignedCms to compute a signature and use it to encode the information in the object into a PKCS#7 message.
ContentInfo contentInfo = new ContentInfo(hashData); // ContentInfo represents the CMS/PKCS #7 ContentInfo data structure.
// Create an instance of the SignedCms class by using the specified content information as the inner content.
SignedCms signedCms = new SignedCms(contentInfo); // SignedCms class enables signing and verifying of CMS/PKCS #7 messages.
CmsSigner cmsSigner = new CmsSigner(cert); // CmsSigner class provides signing functionality.
signedCms.ComputeSignature(cmsSigner, false); // ComputeSignature(CmsSigner) method creates a signature using the specified signer and adds the signature to the CMS/PKCS #7 message. The 2nd parameter which is false prompts the user to select a signing certificate.
byte encoded_msg = signedCms.Encode(); // The Encode method encodes the information in the object named signedCms into a CMS/PKCS #7 message.
If the above code fails because of "System.Security.Cryptography.CryptographicException: A certificate chain could not be built to a trusted root authority" you can try adding the line below immediately before computing the signature and see if it avoids the problem. Ofcourse you can tweak using the other enum options for a check. However this is a temporary workaround and the actual issue of why the chain building failed should be investigated further.
cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly;