EldoS | Feel safer!

Software components for data protection, secure storage and transfer

[Java] PKCS7/CADES countersignatures

Also by EldoS: Callback File System
Create virtual file systems and disks, expose and manage remote data as if they were files on the local disk.
#26700
Posted: 10/03/2013 04:53:23
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hello !

I got some questions about PKCS7 countersigning.

  • If I countersign a file, we can see the countersigner certificate added in the signature file (.p7s). But does this mean that the original file (a PDF for example) is signed by two different people or just that the original signature is countersigned ?
  • How to verify the countersignatures ? Because the TElMessageVerifier, even if I set the VerifyCountersignatures to true, doesn't seem to do so. It can verify the certificates though.

I tried to get the CountersignatureAttributes but it's empty.

Here is the code of my countersigning method :
Code
public void counterSign() throws Exception {
      System.out.println("Countersigning file " + this._fileToSign.getName() + " (" + this._fileToSign.length() + " o)...\n");
      
      try {
         byte[] buf = new byte[(int) this._fileSignature.length()];
         
         try {
            this._fileStream   = new TElFileStream(this._fileSignature.getAbsolutePath(), "rw", true);
            this._fileStream.Read(buf, 0, buf.length);
         }
         catch (Exception e) {
            throw e;
         }
         finally {
            if (this._fileStream != null) {
               this._fileStream.Free();
               this._fileStream.Destroy();
               this._fileStream = null;
            }
         }
      
         Date dateSign = new Date();
         System.out.println("Signature date : " + new SimpleDateFormat("dd/MM/yyyy HH:mm").format(dateSign) + "\n");
         
         TElMessageSigner signer = new TElMessageSigner();
         signer.SetCertStorage(this._certStorage);
         signer.SetSignatureType(TSBMessageSignatureType.mstPublicKey);
         signer.SetIncludeCertificates(true);
         signer.SetIncludeChain(true);
         signer.SetHashAlgorithm(SBConstants.SB_ALGORITHM_DGST_SHA1);
         signer.SetSigningOptions((short) (signer.GetSigningOptions() | SBMessages.soInsertSigningTime));
         signer.SetSigningTime(new Date());
         
         TSBInteger iSize   = new TSBInteger();
         byte[] outBuf      = new byte[0];
         
         signer.Countersign(buf, outBuf, iSize);
         
         outBuf = new byte[iSize.Value];
         
         int i = signer.Countersign(buf, outBuf, iSize);
         if (i != 0) {
            throw new Exception("Countersignature failed. Error code : #" + i);
         }
         
         TElFileStream fs = null;
         try {
            fs = new TElFileStream(this._fileSignature.getAbsolutePath(), "rw", true);
            fs.Write(outBuf, 0, iSize.Value);
         }
         catch (Exception e) {
            throw e;
         }
         finally {
            if (fs != null) {
               fs.Free();
            }
         }   
         
         System.out.println("Countersignature done !");
      }
      catch (Exception e) {
         throw e;
      }
   }

The _fileSignature attribute of the class represents the p7s file.

Thank you !

Mickaël
#26702
Posted: 10/03/2013 05:31:27
by Ken Ivanov (EldoS Corp.)

Hello Mickaël,

Straight to your questions.

Quote
If I countersign a file, we can see the countersigner certificate added in the signature file (.p7s). But does this mean that the original file (a PDF for example) is signed by two different people or just that the original signature is countersigned ?

Countersigning (in the sense assumed by PKCS#7 standard and its derivatives) is always made over an existing signature and not the content it covers. However, as the signature contains the hash of the original content, the countersigner implicitly signs that as well.

Quote
How to verify the countersignatures ? Because the TElMessageVerifier, even if I set the VerifyCountersignatures to true, doesn't seem to do so. It can verify the certificates though.

Countersignatures are verified separately from the main signature. To get their individual verification results, please use the GetCountersignatureVerificationResult() method.

Your code seems to be generally correct and should work as you expect it to.
#26704
Posted: 10/03/2013 06:50:04
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Thanks for your help, it seems to work perfectly. I just added this code to my verying method :
Code
int nbCounterSignatures = v.GetCountersignatureCertIDCount();
         if (nbCounterSignatures != 0) {
            System.out.println("\nVerifying " + nbCounterSignatures + " countersignature(s)...");
            
            String errorMsg = "";
            for (int i = 0; i < nbCounterSignatures; i++) {
               int resCounterSign = v.GetCountersignatureVerificationResult(i);
               
               if (resCounterSign != 0) {
                  errorMsg = "\t- Verification failed for countersignature n°" + (i + 1) + ". Error code : #" + resCounterSign + "\n";
               }
               else {
                  System.out.println("\t- Verification OK for countersignature n°" + (i + 1) + ".");
               }
            }
            
            if (!errorMsg.isEmpty()) {
               throw new Exception(errorMsg);
            }
         }


Just have some other questions though :
  • Is it possible to get the signing time of a countersignatures ? In my original post, you can see that I setted a signing time for the countersignatures and that the countersignature attributes are empty.
  • Is there another way to check if there is countersignatures ? For now I used the GetCountersignatureCertIDCount.
#26705
Posted: 10/03/2013 06:55:27
by Vsevolod Ievgiienko (EldoS Corp.)

Quote
Is it possible to get the signing time of a countersignatures ? In my original post, you can see that I setted a signing time for the countersignatures and that the countersignature attributes are empty.

You should turn on soInsertSigningTime option using TElMessageSigner.SetSigningOptions() method.

Quote
Is there another way to check if there is countersignatures ? For now I used the GetCountersignatureCertIDCount.

Currently its the only way to check this.
#26707
Posted: 10/03/2013 09:52:30
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Quote
Vsevolod Ievgiienko wrote:
You should turn on soInsertSigningTime option using TElMessageSigner.SetSigningOptions() method.

Already did actually. Here is the sample code of my countersigning method :
Code
public void counterSign() throws Exception {
      System.out.println("Countersigning file " + this._fileToSign.getName() + " (" + this._fileToSign.length() + " o)...\n");
      
      try {
         byte[] buf = new byte[(int) this._fileSignature.length()];
         
         try {
            this._fileStream   = new TElFileStream(this._fileSignature.getAbsolutePath(), "rw", true);
            this._fileStream.Read(buf, 0, buf.length);
         }
         catch (Exception e) {
            throw e;
         }
         finally {
            if (this._fileStream != null) {
               this._fileStream.Free();
               this._fileStream.Destroy();
               this._fileStream = null;
            }
         }
      
         Date dateSign = new Date();
         System.out.println("Signature date : " + new SimpleDateFormat("dd/MM/yyyy HH:mm").format(dateSign) + "\n");
         
         TElMessageSigner signer = new TElMessageSigner();
         signer.SetCertStorage(this._certStorage);
         signer.SetSignatureType(TSBMessageSignatureType.mstPublicKey);
         signer.SetIncludeCertificates(true);
         signer.SetIncludeChain(true);
         signer.SetHashAlgorithm(SBConstants.SB_ALGORITHM_DGST_SHA1);
         [B]signer.SetSigningOptions((short) (signer.GetSigningOptions() | SBMessages.soInsertSigningTime));[/B]
         signer.SetSigningTime(new Date());
         
         TSBInteger iSize   = new TSBInteger();
         byte[] outBuf      = new byte[0];
         
         signer.Countersign(buf, outBuf, iSize);
         
         outBuf = new byte[iSize.Value];
         
         int i = signer.Countersign(buf, outBuf, iSize);
         if (i != 0) {
            throw new Exception("Countersignature failed. Error code : #" + i);
         }
         
         TElFileStream fs = null;
         try {
            fs = new TElFileStream(this._fileSignature.getAbsolutePath(), "rw", true);
            fs.Write(outBuf, 0, iSize.Value);
         }
         catch (Exception e) {
            throw e;
         }
         finally {
            if (fs != null) {
               fs.Free();
            }
         }   
         
         System.out.println("Countersignature done !");
      }
      catch (Exception e) {
         throw e;
      }
   }
#26716
Posted: 10/04/2013 03:36:55
by Vsevolod Ievgiienko (EldoS Corp.)

Please consider using TElSignedCMSMessage class instead of TElMessageSigner to generate countersignatures. Indeed countersignatures support is very limited in TElMessageSigner and not all features are supported.
#26759
Posted: 10/08/2013 09:57:37
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hey again !

So I used TElSignedCMSMessage not just to countersign but also to sign and verify the signatures. It works smoothly, I just got a question :

Is there another way to get the TElX509Certificate that signed/countersigned the data that the one I use (see below) ?

Method that verify signatures :
Code
public void verifSign() throws Exception {
      System.out.println("Verifying signature for file " + this._fileToSign.getName() + " (" + this._fileToSign.length() + " o)...");
      
      SimpleDateFormat simpleDF = new SimpleDateFormat("dd/MM/yyyy HH:mm");
      
      try {
         try {
            this._fileStream = new TElFileStream(this._fileSignature.getAbsolutePath(), "r", true);
         }
         catch (Exception e) {
            throw e;
         }
         
         TElSignedCMSMessage cms = new TElSignedCMSMessage();
         cms.Open(this._fileStream, null, 0, 0);
         int nbSign                     = cms.GetSignatureCount();
         TElCustomCertStorage certStorage   = cms.GetCertificates();
         
         if (nbSign != 0) {
            System.out.println("\t" + nbSign + " found...");

            for (int i = 0; i < nbSign; i++) {
               System.out.println("\tChecking signature n°" + (i + 1) + " :\n");
               
               TElCMSSignature sig            = cms.GetSignature(i);
               int nbCounterSig            = sig.GetCountersignatureCount();
               TElX509Certificate signerCert   = this._getSigningX509Cert(sig.GetSigningCertificate(), certStorage);
               
               System.out.println("\t\t- Validity : " + ((sig.Validate() == TSBCMSSignatureValidity.csvValid) ? "valid" : "invalid"));
               System.out.println("\t\t- Signing time : " + simpleDF.format(sig.GetSigningTime()));
               System.out.println("\t\t- Certificate : " + signerCert.GetSubjectName().CommonName);
               
//               Certificat cert = new Certificat(certStorage, signerCert);
//               cert.validate(false, sig.GetSigningTime());
               
               System.out.println("\t\t- Countersignature(s) : " + nbCounterSig);
               
               if (nbCounterSig != 0) {
                  for (int j = 0; j < nbCounterSig; j++) {
                     System.out.println("\t\tChecking countersignature n°" + (j + 1) + " :\n");
                     
                     TElCMSSignature counterSig            = sig.GetCountersignature(j);
                     TElX509Certificate countersignerCert   = this._getSigningX509Cert(counterSig.GetSigningCertificate(), certStorage);
                     
                     System.out.println("\t\t\t- Validity : " + ((counterSig.Validate() == TSBCMSSignatureValidity.csvValid) ? "valid" : "invalid"));
                     System.out.println("\t\t\t- Countersigning time : " + simpleDF.format(counterSig.GetSigningTime()));
                     System.out.println("\t\t\t- Certificate : " + countersignerCert.GetSubjectName().CommonName);
                     
//                     cert.setCertificate(countersignerCert);
//                     cert.validate(false, counterSig.GetSigningTime());
                  }
               }
            }
         }
         else {
            System.out.println("No signatures.");
         }
      }
      catch (Exception e) {
         throw e;
      }
      finally {
         if (this._fileStream != null) {
            this._fileStream.Free();
            this._fileStream.Destroy();
            this._fileStream = null;
         }
      }
   }


Method that gets the TElX509Certificate that signed the data :
Code
/**
    * Récupère le TElX509Certificate avec lequel la signature a été effectuée.
    * @param   CMSsignerCert      le certificat de signature
    * @param   signerCertStorage   le TElCustomCertStorage contenant le(s) certificat(s) de signature/countersignature
    * @return   le TElX509Certificate avec lequel la signature a été effectuée
    */
   private TElX509Certificate _getSigningX509Cert(TElCMSSigningCertificate CMSsignerCert, TElCustomCertStorage signerCertStorage) throws Exception {
      TElX509Certificate signerCert = null;
      
      for (int i = 0; i < signerCertStorage.GetCount(); i++) {
         if (CMSsignerCert.Corresponds(signerCertStorage.GetCertificate(i))) {
            signerCert = signerCertStorage.GetCertificate(i);
            break;
         }
      }
      
      return signerCert;
   }


Thanks !
#26760
Posted: 10/09/2013 02:03:47
by Vsevolod Ievgiienko (EldoS Corp.)

The can use TElCMSSignature.CertificateValues propertry to read signing certificates.
#26820
Posted: 10/15/2013 09:38:47
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hello !

I tried to use TElCMSSignature.GetCergtificateValues() but the TElCustomCertStorage that it returns is always empty (for signatures and countersignatures) while the TElSignedCMSMessage.GetCertificates() method gives me all the certificates use to sign and/or countersign.

Do you have any idea why ?

Thanks !
#26823
Posted: 10/15/2013 10:32:42
by Ken Ivanov (EldoS Corp.)

Hello,

A PKCS#7/CMS signature format provides several locations where the signing certificates can be placed by the signer. A classic approach is to use the PKCS#7 blob-wide certificates store, which is accessible via the TElSignedCMSMessage.GetCertificates() method. CMS/CAdES standards declare an additional per-signature attribute ('certificate-values'), which can also be used to store signature-specific certificates. Certain CAdES subformats (e.g. CAdES-A) require the signer's certificate chain to be put (or duplicated) in the 'certificate-values' attribute. The contents of the 'certificate-values' attribute is returned by the TElCMSSignature.GetCertificateValues() method.

This way, it is normal to get an empty certificate list from TElCMSSignature.GetCertificateValues() and a non-empty one from TElSignedCMSMessage.GetCertificates() - it only means that the signer follows classic approach and does not need to comply to advanced CAdES subformats.
Also by EldoS: Rethync
The cross-platform framework that simplifies synchronizing data between mobile and desktop applications and servers and cloud storages

Reply

Statistics

Topic viewed 5244 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!