I have a set of questions:
What does a .p7s file contain? I read that it usually is an encrypted message sent to an e-mail, but in my case I have a file and a .p7s file on my hdd. The file is much larger than the .p7s, so I am wondering what is in it (and of course how to later use it).
2.this question occurs mostly because I have no naswer for 1. - If I have my public key in the form of a byte array, how can I verify the signature in C#? I found this on the internet, but again, it uses some text gotten from an e-mail and I honestly don't know what is happening:
public static bool Verify(byte[] signature, string text)
{
X509Certificate2 certificate = new X509Certificate2(#"D:\My-CV.docx.p7s");
if (signature == null)
throw new ArgumentNullException("signature");
if (certificate == null)
throw new ArgumentNullException("certificate");
//hash the text
// Methode 3 for Hashing
System.Security.Cryptography.SHA1 hash3 = System.Security.Cryptography.SHA1.Create();
System.Text.UnicodeEncoding encoder = new System.Text.UnicodeEncoding();
byte[] combined = encoder.GetBytes(text);
byte[] hash3byte = hash3.ComputeHash(combined);
//Adding the text from the email, to a contentInfo
ContentInfo content = new ContentInfo(hash3byte);
// decode the signature
SignedCms verifyCms = new SignedCms(content, true);
verifyCms.Decode(signature);
// verify it
try
{
verifyCms.CheckSignature(new X509Certificate2Collection(certificate), false);
return true;
}
catch (CryptographicException)
{
return false;
}
}
Can someone help me with this?
The .p7s file is containing the signature of your document. The content is not encrypted, but it's look like.
The document file is much larger, because it contains the date, the .p7s the signature.
To check the signature, you need the public part of the certificate with which the document was signed.
You can check this two posts to check the signature :
Check signature for x509 certificate
In C#, sign an xml with a x.509 certificate and check the signature
The last thing is to load the signature data, from the p7s file.
I make some search, and come back to you.
Related
I try to sign a pdf file using my smartcard (USB token) but encounter "Document has been altered or corrupted since it was signed" error when I open the signed pdf file in Adobe. The error is not so descriptive and I'm not sure where to look at because the code seems good to me but apparently it's not..
The code that I use is:
var signer = smartCardManager.getSigner("myTokenPassword");
var toBeSignedHash = GetHashOfPdf(File.ReadAllBytes(#"xxx\pdf.pdf"), cert.asX509Certificate2().RawData, "dsa", null, false);
var signature = signer.sign(toBeSignedHash);
var signedPdf = EmbedSignature(cert.getBytes(), signature);
File.WriteAllBytes(#"xxx\signedpdf.pdf", signedPdf);
public byte[] GetHashOfPdf(byte[] unsignedFile, byte[] userCertificate, string signatureFieldName, List<float> location, bool append)
{
byte[] result = null;
var chain = new List<Org.BouncyCastle.X509.X509Certificate>
{
Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(new X509Certificate2(userCertificate))
};
Org.BouncyCastle.X509.X509Certificate certificate = chain.ElementAt(0);
using (PdfReader reader = new PdfReader(unsignedFile))
{
using (var os = new MemoryStream())
{
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0', null, append);
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(0,0,0,0), 1, signatureFieldName);
appearance.Certificate = certificate;
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 8192);
Stream data = appearance.GetRangeStream();
byte[] hash = DigestAlgorithms.Digest(data, "SHA256");
var signatureContainer = new PdfPKCS7(null, chain, "SHA256", false);
byte[] signatureHash = signatureContainer.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
result = DigestAlgorithms.Digest(new MemoryStream(signatureHash), "SHA256");
this.hash = hash;
this.os = os.ToArray();
File.WriteAllBytes(#"xxx\temp.pdf", this.os);
}
}
return result;
}
public byte[] EmbedSignature(byte[] publicCert, byte[] sign)
{
var chain = new List<Org.BouncyCastle.X509.X509Certificate>
{
Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(new X509Certificate2(publicCert))
};
var signatureContainer = new PdfPKCS7(null, chain, "SHA256", false);
using (var reader = new PdfReader(this.os))
{
using (var os2 = new MemoryStream())
{
signatureContainer.SetExternalDigest(sign, null, "RSA");
byte[] encodedSignature = signatureContainer.GetEncodedPKCS7(this.hash, null, null, null, CryptoStandard.CMS);
IExternalSignatureContainer external = new MyExternalSignatureContainer(encodedSignature);
MakeSignature.SignDeferred(reader, "dsa", os2, external);
return os2.ToArray();
}
}
}
The pdf file that I try to sign is this.
Temp pdf file that is created after adding signature fields is this.
Signed pdf file is this.
Base64 format of the hash that is signed is: klh6CGp7DUzayt62Eusiqjr1BFCcTZT4XdgnMBq7QeY=
Base64 format of the signature is: Uam/J6W0YX99rVP4M9mL9Lg9l6YzC2yiR4OtJ18AH1PtBVaNPteT3oPS7SUc+6ak2LfijgJ6j1RgdLamodDPKl/0E90kbBenry+/g1Ttd1bpO8lqTn1PWJU2TxeGHwyRyaFBOUga2AxpErIHrwxfuKCBcodB7wvAqRjso0jovnyP/4DluyOPm97QWh4na0S+rtUWOdqVmKGOuGJ3sBXuk019ewpvFcqWBX4Mvz7IKV56wcxQVQuJLCiyXsMXoazwyDCvdteaDz05K25IVwgEEjwLrppnc/7Ue9a9KVadFFzXWXfia7ndmUCgyd70r/Z+Oviu9MIAZL8GuTpkD7fJeA==
I use hex encoding of byte arrays here. Your base64 encoded hash
klh6CGp7DUzayt62Eusiqjr1BFCcTZT4XdgnMBq7QeY=
in hex encoding is equal to
92587A086A7B0D4CDACADEB612EB22AA3AF504509C4D94F85DD827301ABB41E6
###In short
Your code hashes the signed attributes twice. Simply don't hash the bytes returned by signatureContainer.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS) in GetHashOfPdf but instead use the authenticated attribute bytes themselves as return value.
###In detail
Analyzing the signature in your example PDF it turns out that
indeed the hash of the signed attributes is
92587A086A7B0D4CDACADEB612EB22AA3AF504509C4D94F85DD827301ABB41E6
but the hash in the RSA encrypted DigestInfo object of the signature is
1DC7CAA50D88243327A9D928D5FB4F1A61CBEFF9E947D393DDA705BD61B67F25
which turns out to be the hash of the before mentioned hash of the signed attributes.
Thus, your
var signature = signer.sign(toBeSignedHash);
call appears to hash the toBeSignedHash value again.
The most simple fix would be to replace
byte[] signatureHash = signatureContainer.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
result = DigestAlgorithms.Digest(new MemoryStream(signatureHash), "SHA256");
by
result = signatureContainer.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
in GetHashOfPdf to have only signer.sign do the hashing.
###Analyzing such issues
In a comment you asked
how did you figure all this out :)?
Well, yours is not the first question with a customized iText signing process resulting in errors or at least unwanted profiles.
In the course of the analysis of those questions the first step usually is to extract the embedded signature container and inspect it in an ASN.1 viewer.
In case of your PDF the main result of that inspection was that the signature as such looked ok and that your signed attributes don't contain any variable data.
If there had been some variable data (e.g. a signing time attribute) in them, a candidate for the cause of the issue would have been that you build the signed attributes twice, once explicitly in GetHashOfPdf, once implicitly in EmbedSignature, with different values for the variable data. But as mentioned above, this was not the case.
The next step here was to actually check the hashes involved. Checking the document hash is simple, one calculates the signed byte range hash and compares with the value of the MessageDigest signed attribute, cf. the ExtractHash test testSotnSignedpdf (in Java).
The result for your PDF turned out to be ok.
The following step was to inspect the signature container more thoroughly. In this context I once started to write some checks but did not get very far, cf. the SignatureAnalyzer class. I extended it a bit for the test of the hash of the signed attributes making use of the signature algorithm you used, the old RSASSA-PKCS1-v1_5: In contrast to many other signature algorithms, this one allows to trivially extract the signed hash.
Here the result for your PDF turned out not to be ok, the hash of the signed attributes differed from the signed hash.
There are two often seen causes for a mismatch here,
either the signed attributes are signed with a wrong encoding (it must be the regular DER encoding, not some arbitrary BER encoding and in particular not an encoding with the implicit tag the value stored in the signature has --- even larger players do this wrong sometimes, e.g. Docusign, cf. DSS-1343)
or the hash was somehow transformed during signing (e.g. the hash is base64 encoded or hashed again).
As it turned out, the latter was the case here, the hash was hashed again.
Trying to validate PDF signature isn't working. The PDF were signed by Adobe Acrobat and then trying to verify it with the public key of the client certificate.
So I get the public key of the client certificate, hash the PDF and verify if the hash is equal to the pdf signature, but it fails.
HttpClientCertificate cert = request.ClientCertificate;
X509Certificate2 cert2 = new X509Certificate2(cert.Certificate);
PdfReader pdfreader = new PdfReader("path_to_file");
AcroFields fields = pdfreader.AcroFields;
AcroFields.Item item = fields.GetFieldItem("Signature1");
List<string> names = fields.GetSignatureNames();
foreach (string name in names){
PdfDictionary dict = fields.GetSignatureDictionary(name);
PdfPKCS7 pkcs7 = fields.VerifySignature(name);
Org.BouncyCastle.X509.X509Certificate pdfSign = pkcs7.SigningCertificate;
// Get its associated CSP and public key
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert2.PublicKey.Key;
// Hash the data
SHA256 sha256 = new SHA256Managed();
byte[] pdfBytes = System.IO.File.ReadAllBytes("path_to_pdf");
byte[] hash = sha256.ComputeHash(pdfBytes);
// Verify the signature with the hash
bool ok = csp.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA256"), pdfSing.GetSignature());
}
First, to verify whether the signature correctly you can simply use the PdfPKCS7 object you already retrieved, more exactly its Verify method:
/**
* Verify the digest.
* #throws SignatureException on error
* #return <CODE>true</CODE> if the signature checks out, <CODE>false</CODE> otherwise
*/
virtual public bool Verify()
Thus, you can simply call
bool ok = pkcs7.Verify();
and ok is true only if the document hash matches the hash in the signature.
Concerning your attempt to calculate the document hash like this
byte[] pdfBytes = System.IO.File.ReadAllBytes("path_to_pdf");
byte[] hash = sha256.ComputeHash(pdfBytes);
This indeed gives you the hash value of the complete PDF.
For document types with integrated signatures like PDFs, though, this is not the hash of interest because the complete PDF obviously includes the integrated signature!
Thus, you have to find the space reserved for the signature in the PDF and ignore it during hash calculation, cf. this answer on Information Security Stack Exchange, in particular this image:
In case of multiple signatures you furthermore have to consider that the earlier signatures only sign a former revision of the PDF, so the hash is to be calculated only for a starting segment of the file, cf. this image from the answer referenced above:
The iText(Sharp) method PdfPKCS7.Verify() takes all this into account.
i have a large file that needs to be signed in order to be archived. It's a CSV file that is generated once in a month and has a size of > 2Gb (don't ask me what this is good for :) ).
Anyway.. The signing of the file is not the problem, there is a lib for that, i generate the hash and i get my signature.
What i want to do now, is to verify the signature.
tutorials want me to do something like this:
byte[] sig = ReadFile(signatureFile);
SignedCms cms = new SignedCms(new ContentInfo(ReadFile(dataFile)), true);
cms.Decode(sig);
cms.CheckSignature(false);
this actually works.. but as you can imagine, i don't feel like loading the entire content of a 2 GB file into memory.
the msdn article about the ContentInfo class tells me, that i can choose the oid for the content, i want my contentInfo initialized with.
the oid for hashed data would be "1.2.840.113549.1.7.5"
so here i am:
byte[] sig = ReadFile(signatureFile);
SignedCms cms = new SignedCms(new ContentInfo(new byte[]{}), true);
cms.Decode(sig);
SignerInfo inf = cms.SignerInfos[0];
string algorithm = inf.DigestAlgorithm.FriendlyName;
cms = new SignedCms(new ContentInfo(new Oid("1.2.840.113549.1.7.5"), GetHash(algorithm, dataFile)), true);
cms.Decode(sig);
cms.CheckSignature(false);
now CheckSignature throws me an exception saying that the hash is incorrect.
the following would work:
byte[] sig = ReadFile(signatureFile);
SignedCms cms = new SignedCms(new ContentInfo(new byte[]{}), true);
cms.Decode(sig)
byte[] compareableHash = GetHash(algorithm, dataFile);
foreach (var t in inf.SignedAttributes)
{
if (t.Oid.Value == "1.2.840.113549.1.9.4")
{
Pkcs9MessageDigest digest = (Pkcs9MessageDigest)t.Values[0];
if (CompareableHash(compareableHash, digest.MessageDigest)) // this compares the hashes bytewise
{
Console.WriteLine("hash is correct!");
}
}
}
can i trust this method to be 100% reliable or is there a better way?
I have a signed PDF file. With this function, which makes use of iTextSharp library, I find the certificates p7m signatures:
private void GetSignature(string FileName)
{
AcroFields acroFields = new PdfReader(FileName).AcroFields;
List<string> names = acroFields.GetSignatureNames();
foreach (var name in names)
{
PdfDictionary dict = acroFields.GetSignatureDictionary(name);
PdfString contents = (PdfString)PdfReader.GetPdfObject(dict.Get(PdfName.CONTENTS));
byte[] PKCS7 = contents.GetOriginalBytes();
ByteArrayToFile(#"c:\signature\" + name + ".p7m", PKCS7);
}
}
Now... how can I extract images (bitmap) associated to the signatures? Is it possible?
Thanks, Luigi
In your sample documents the term signature applies threefold:
It contains digital signatures according to the PDF specification ISO 32000-1:2008.
The respective visualization contains a bitmap image of an handwritten signature.
The respective signature dictionary contains proprietary information by the software which added all the signature data to the PDF. Most likely these proprietary information contain the biometric data mentioned in the comments of the OP.
According to the manufacturer of the software creating these multi-level signatures, the handwritten signature seems like the major proof of identity. The digital one only serves to protect the document from changes; it does not necessarily reflect the identity of the person who signed manually but instead of the owner of the device on which that manual signature was created ("Please sign here that you got the parcel"):
Functions
Handwritten Signature Capturing - Forensically identifiable signatures on signature pads, payment terminals, the iPad or Android devices.
Signature Verification - Compare a handwritten signature against a pre-enrolled profile.
Control all steps in the signing process - Including positioning signature fields, filling out forms, adding annotations, adding attachments, and much more.
Protects the Integrity of Documents - By sealing them with a digital signature.
(xyzmo English website start page)
Concerning the extraction of all these information using iText...
The properties of the digital signature can easily be extracted and verified as already observed by the OP using the signature related methods of the AcroFields class.
The bitmap image of the handwritten signature can also be extracted fairly easily. The appearance stream of the signature form field dictionary merely paints that bitmap which is attached to the stream as a resource.
The data container containing the proprietary information can also be extracted as it is the value of just another key in the signature dictionary.
Unfortunately, though, the contents of that data container are packed into a XML fragment calling itself EncryptedSignatureDataContainer. Whether the payload data of this XML fragment can be properly decrypted and how it is to be interpreted is information to request from the xyzmo people themselves, and I have no idea if they consider that information public or not.
Thus, the most relevant information is the least accessible one.
PS Concerning the decryption of the encrypted biometric payload I found the following on the manufacturer's website:
The document contains a captured signature that has been encrypted (RSA 4096 + AES256). A person’s signature is encrypted immediately as it is captured by the signature pad, using the private key of a special certificate. This special certificate is selected by the company using the xyzmo suite, and is typically stored in a secure environment outside the company (bank safe, external notary, etc.). Thus, xyzmo itself has NO access to this certificate. For the encryption of signatures, the xyzmo suite just needs the public key of the certificate. It is only for decryption, and the extraction of signatures from a document, that the private key is required. Only specific people, to whom the company has granted access to this certificate, will be able to decrypt the profile using the PenAnalyst tool, which is provided as part of the suite.
(xyzmo English website Digital Signature Capture FAQ's)
Thus, to decrypt the biometric data you have to have access to the respective private key which is typically stored in a secure environment outside the company (bank safe, external notary, etc.). If you have that kind of access, we may continue talking about the format of those decrypted data... ;)
BTW, if anyone could simply retrieve the biometric data from the signed document, they could too easily be copied to other documents to fake a signature.
Extracting the bitmap image of the handwritten signature
As there was special interest in the extraction of the bitmap image of the handwritten signature, here a quick and dirty helper to extract the image of the signature. As already said, I do it in Java as I'm more at home there:
public class XyzmoSignatureDataExtractor
{
public XyzmoSignatureDataExtractor(PdfReader reader)
{
this.reader = reader;
}
public PdfImageObject extractImage(String signatureName) throws IOException
{
MyImageRenderListener listener = new MyImageRenderListener();
PdfDictionary sigFieldDic = reader.getAcroFields().getFieldItem(signatureName).getMerged(0);
PdfDictionary appearancesDic = sigFieldDic.getAsDict(PdfName.AP);
PdfStream normalAppearance = appearancesDic.getAsStream(PdfName.N);
PdfDictionary resourcesDic = normalAppearance.getAsDict(PdfName.RESOURCES);
PdfContentStreamProcessor processor = new PdfContentStreamProcessor(listener);
processor.processContent(ContentByteUtils.getContentBytesFromContentObject(normalAppearance), resourcesDic);
return listener.image;
}
class MyImageRenderListener implements RenderListener
{
public void beginTextBlock() { }
public void endTextBlock() { }
public void renderImage(ImageRenderInfo renderInfo)
{
try
{
image = renderInfo.getImage();
}
catch (IOException e)
{
throw new RuntimeException("Failure retrieving image", e);
}
}
public void renderText(TextRenderInfo renderInfo) { }
PdfImageObject image = null;
}
final PdfReader reader;
}
You use it like this:
PdfReader reader = new PdfReader(resourceStream);
XyzmoSignatureDataExtractor extractor = new XyzmoSignatureDataExtractor(reader);
AcroFields acroFields = reader.getAcroFields();
for (String name: acroFields.getSignatureNames())
{
System.out.printf("\nTesting signature '%s'.\n", name);
PdfImageObject image = extractor.extractImage(name);
OutputStream os = new FileOutputStream("target/test-outputs/SampleXyzmoSignature-image-" + name + "." + image.getFileType());
os.write(image.getImageAsBytes());
os.close();
PdfDictionary imageDictionary = image.getDictionary();
PRStream maskStream = (PRStream) imageDictionary.getAsStream(PdfName.SMASK);
if (maskStream != null)
{
PdfImageObject maskImage = new PdfImageObject(maskStream);
os = new FileOutputStream("target/test-outputs/SampleXyzmoSignature-image-" + name + "-mask." + maskImage.getFileType());
os.write(maskImage.getImageAsBytes());
os.close();
}
}
Warning: The class XyzmoSignatureDataExtractor really is a quick&dirty hack. Many assumptions are made, null-checks are left out, ...
I receive an XML document as a string parameter in my method. The XML document is:
<Document>
<ZipContainer> Zip_File_In_Base64 </ZipContainer>
<X509Certificate> Certificate_In_Base64 </X509Certificate>
</Document>
From this string I extract the ZIP file in base64 format and X509Certificate2 certificate in base64 format. The ZIP file contains:
file describing the contents of the ZIP file as XML (file packageDescription.xml);
files with the contents of transmitted documents (for example, *.doc files);
files with content of detached digital signature (*.p7s files - detached digital signature);
From the archive should be extracted signature that signed documents (detached digital signature may be more than one). Detached digital signature are stored in files with .p7s extension. Each signature must be done to check its agreement with digital signature, with which the user is logged in to the portal.
The must consist of two steps:
See method certificateValidator() (see this method below): This is a of detached signature, contained in the .p7s files with their corresponding files that are signed, these *. P7s-files.
For example: a pair of related files: ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s and
ZayavUL_3594c921f545406d9b8734bbe28bf894.doc.
See method certificateValidator(): This verifies certificate from a file .p7s with a certificate that is extracted from the XML document input string.
Questions
The method signatureValidator (see this method below) is not currently used detached signature of the files .p7s. I did try, but without success. How do I properly verify the detached signature of .p7s file for its corresponding file?
In the method certificateValidator (see this method below) how do I verify the conformity of the certificate extracted from the .p7s file, with a certificate extracted from input string in Base64 format?
The line of code foreach (X509Certificate2 x509 in signCms.Certificates) { } ---> Certificates Collection always is empty. Why?
Input parameters
Dictionary <string, byte[]> dictP7SFiles (key - the name of the file *.p7s, value - array of bytes, representing *.p7s file)
Dictionary <string, byte[]> dictNotP7SFiles (key - the name of the file that is signed using detached signature from *.p7s file, value - array of bytes, representing file)
X509Certificate2 userCertX509 - certificate object, extracted from the input xml-document (where it has the format Base64)
Code
Here below are testing implementation of verification steps (see above this 2 steps):
private bool certificateValidator(Dictionary<string, byte[]> dictP7SFiles,
Dictionary<string, byte[]> dictNotP7SFiles, X509Certificate2 userCertX509)
{
bool isValid = false;
try
{
foreach (KeyValuePair<string, byte[]> pair in dictP7SFiles)
{
ContentInfo contentInfo = new ContentInfo(pair.Value);
SignedCms signCms = new SignedCms(contentInfo, true);
if (signCms.Certificates.Count != 0)
{
//Certificates Collection always is empty. Why?
foreach (X509Certificate2 x509 in signCms.Certificates)
{
if ((x509.SerialNumber != userCertX509.SerialNumber)
|| (x509.Thumbprint != userCertX509.Thumbprint))
{
isValid = false;
return isValid;
}
}
isValid = true;
return isValid;
}
}
}
catch (Exception ex)
{
//here process exception code
}
return isValid;
}
private bool signatureValidator(Dictionary<string, byte[]> dictP7SFiles,
Dictionary<string, byte[]> dictNotP7SFiles, X509Certificate2 userCertX509)
{
bool isValid = false;
try
{
byte[] data = dictP7SFiles["ZayavUL_3594c921f545406d9b8734bbe28bf894.doc"];
byte[] publicKey;
byte[] signature;
object hasher = SHA1.Create(); // Our chosen hashing algorithm.
// Generate a new key pair, then sign the data with it:
using (var publicPrivate = new RSACryptoServiceProvider())
{
signature = publicPrivate.SignData(data, hasher);
publicKey = publicPrivate.ExportCspBlob(false); // get public key
}
// Create a fresh RSA using just the public key, then test the signature.
using (var publicOnly = new RSACryptoServiceProvider())
{
publicOnly.ImportCspBlob(publicKey);
isValid = publicOnly.VerifyData(data, hasher, signature); // Return True
//isValid = ByteArrayCompare(dictP7SStreams["ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s"], signature);
byte[] p7sDetachedSignature = File.ReadAllBytes(#"D:\ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s");
isValid = ByteArrayCompare(p7sDetachedSignature, signature);
}
}
catch (Exception)
{
//here process exception code
}
return isValid;
}
The main thing you are doing wrong is to regenerate the CMS and signature. You should parse the CMS message, then indicate the external content during verification.
How do I properly verify the detached signature of .p7s file for its corresponding file?
Take a look at the following Java code on SO to see how to verify signatures; C# should use the same architecture and it should therefore work similarly.
In the method certificateValidator (see this method below) how do I verify the conformity of the certificate extracted from the .p7s file, with a certificate extracted from input string in Base64 format?
Decode the base 64 certificate and perform chain verification and validation of the certificate. How much validation you want to perform (e.g. checking the effective date) is up to you.
The line of code foreach (X509Certificate2 x509 in signCms.Certificates) { } ---> Certificates Collection always is empty. Why?
You simply didn't put one in during construction of the new CMS structure.
You certainly should not regenerate the signature either. Normally you would not have the private key during verification, and the algorithm may not match the one used within the CMS document. Furthermore, even if it would, signature generation is not always deterministic (you may get different signature values).