EldoS | Feel safer!

Software components for data protection, secure storage and transfer

[Java] PDF signing : "No signing certifcate"

Also by EldoS: CallbackProcess
A component to control process creation and termination in Windows and .NET applications.
#25537
Posted: 07/04/2013 10:32:23
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hi,

I'm trying to sign PDF documents with my company's applet. I retrieve the signing certificate from the Windows keystore (in fact, I display all the certificates installed in there and the user selects his signing certificate). For now, I'm trying with a certificate which is on a smart card. So i get an X509Certificate object and I create a TElX509Certificate from it, add the private key and add the TElX509Certificate in a TElMemoryCertStorage. Then I try to sign the document with that.
But then I get this Exception :
Quote
Exception in thread "Thread-17" SecureBlackbox.PKIPDF.EElPDFAdvancedPublicKeySecurityHandlerError: No signing certificate
at SecureBlackbox.PKIPDF.TElPDFAdvancedPublicKeySecurityHandler.GetEstimatedSignatureSize(SBPAdES.pas:2198)
at SecureBlackbox.PDF.TElPDFDocument.$PreCalculateSignatures$3947$SetupSignatureInfo(SBPDF.pas:6974)
at SecureBlackbox.PDF.TElPDFDocument.PreCalculateSignatures(SBPDF.pas:8864)
at SecureBlackbox.PDF.TElPDFDocument.Close(SBPDF.pas:5932)
at awsoutil.outil.signature.pades.SignFile_SignThread.run(SignFile_SignThread.java:147)


Seems like the private key isn't in the TElX509Certificate object because TElX509Certificate.GetPrivateKeyExists() returns false.

What could be the problem here ?

Also, I don't have the problem when doing PKCS7 signatures with BouncyCastle libraries. But when signing that way, a little window opens and asks me to put the certificate's PIN code, which is not the case when trying to sign with SecureBlackbox.

Here is the code (with some comments) :
Code
TElX509Certificate signCertificate = new TElX509Certificate();
signCertificate.LoadFromBuffer(this._x509Certificate.getEncoded());
signCertificate.LoadKeyFromBuffer(this._x509CertPrivatekey.getEncoded());
         
AppletAWS.println("\nDN certificate from X509Certificate object : " + this._x509Certificate.getSubjectDN().getName()); // displays DN from X509Certificate
AppletAWS.println("DN certificate from TElX509Certificate object : " + signCertificate.GetSubjectRDN().SaveToDNString() + "\n"); // displays DN from TElX509Certificate
AppletAWS.println("Certificate private key from java.security.PrivateKey : " + this._x509CertPrivatekey + "\n"); // displays some key informations
AppletAWS.println("Certificate private key exists : " + signCertificate.GetPrivateKeyExists() + "\n"); // displays false
AppletAWS.println("Certificate private key extractable : " + signCertificate.GetPrivateKeyExists() + "\n"); // displays false
         
TElMemoryCertStorage signCertsStorage = new TElMemoryCertStorage();
signCertsStorage.Clear();
signCertsStorage.Add(signCertificate, true); // What is the second parameter used for ?
         
TElPDFAdvancedPublicKeySecurityHandler handler = new TElPDFAdvancedPublicKeySecurityHandler();
//handler.SetSignatureType(TSBPDFPublicKeySignatureType.pstPKCS7SHA1);
handler.SetPAdESSignatureType(TSBPAdESSignatureType.pastBasic);
handler.SetCertStorage(signCertsStorage);
handler.SetTSPClient(null);
handler.SetAutoCollectRevocationInfo(true);
handler.SetIgnoreChainValidationErrors(true);
handler.SetIgnoreTimestampFailure(true);

int signIndex         = pdfStream.AddSignature();
TElPDFSignature sign   = pdfStream.GetSignatureEntry(signIndex);
sign.SetHandler(handler);
sign.SetInvisible(false);
sign.SetSigningTime(new Date());
         
pdfStream.Close(true); // where the application fails

Thanks !

Mickaël
#25538
Posted: 07/04/2013 10:51:07
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hey again,

Forgot to say that the private key is loaded form a java.security.PrivateKey object.
#25539
Posted: 07/04/2013 13:19:37
by Ken Ivanov (EldoS Corp.)

Hello Bénès,

Thank you for contacting us.

The method you use to load the certificate into a TElX509Certificate instance won't work, as hardware tokens normally do not give away private keys. That is, this._x509CertPrivatekey.getEncoded() call is likely to be returning an empty buffer, and thus no key is passed to the TElX509Certificate object.

If the signing certificate is available via a Windows system store, please consider using the TElWinCertStorage class to get it from there. The private key should be retrieved correctly in this case.
#25541
Posted: 07/05/2013 00:27:11
by Vsevolod Ievgiienko (EldoS Corp.)

Hello.

JFYI. The latest build of SecureBlackbox includes special cryptoprovider that allows to use non-exportable private keys for signing/encryption operations. You can use it as an alternative to TElWinCertStorage that Ken recommended above.

In general TElWinCertStorage is easier to use but it requires native JNI module.

Here is the sample code that will allow you to create a working instance of TElX509Certificate:
Code
PrivateKey pk = ...; // Get java.security.PrivateKey somewhere
X509Certificate cert = ...; // Get corresponding certificate

TElJCECryptoProvider cp = (TElJCECryptoProvider) SBCryptoProvJCE.JCECryptoProvider();

TElPublicKeyMaterial km = new TElRSAKeyMaterial(cp); // RSA an DSA are supported at the moment
km.SetKeyPair(new KeyPair(cert.getPublicKey(), pk));

TElX509Certificate x509 = new TElX509Certificate();
x509.FromX509Certificate(cert); // load public part of the certificate that is usually exportable
x509.SetKeyMaterial(km); // set key material that is initialized with non-exportable key
// use x509 for signing/encryption etc. with other SBB components
#25566
Posted: 07/08/2013 06:49:38
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hi.

I chose the second option (for now, later I'll have to use TElCertStorage to get the certificates from the MS keyStore) with the beta version of SecureBlackboc and it works perfectly ! Thanks you guys.

But I have another problem (dunno if I must create another forum thread or not) : the signature validation. No matter which certificate I use to sign, the TElPDFSignature.Validate() function always returns false. The certificate validation is fine though. Could you help me please ?

Here is the code I use to sign the PDF document :
Code
TElJCECryptoProvider cp = (TElJCECryptoProvider) SBCryptoProvJCE.JCECryptoProvider();

TElPublicKeyMaterial km = new TElRSAKeyMaterial(cp); // RSA an DSA are supported at the moment
km.SetKeyPair(new KeyPair(this._x509Certificate.getPublicKey(), this._x509CertPrivatekey));

TElX509Certificate signX509Certificate = new TElX509Certificate();
signX509Certificate.FromX509Certificate(this._x509Certificate); // load public part of the certificate that is usually exportable
signX509Certificate.SetKeyMaterial(km); // set key material that is initialized with non-exportable key

TElMemoryCertStorage signCertsStorage = new TElMemoryCertStorage();
signCertsStorage.Clear();
signCertsStorage.Add(signX509Certificate, true);

TElPDFAdvancedPublicKeySecurityHandler handler = new TElPDFAdvancedPublicKeySecurityHandler();
//handler.SetSignatureType(TSBPDFPublicKeySignatureType.pstPKCS7SHA1);
handler.SetPAdESSignatureType(TSBPAdESSignatureType.pastBasic);
handler.SetCertStorage(signCertsStorage);
handler.SetTSPClient(null);
handler.SetAutoCollectRevocationInfo(true);
handler.SetIgnoreChainValidationErrors(true);
handler.SetIgnoreTimestampFailure(true);

int signIndex      = pdfStream.AddSignature();
TElPDFSignature sign   = pdfStream.GetSignatureEntry(signIndex);
sign.SetHandler(handler);
sign.SetInvisible(false);
sign.SetSigningTime(new Date());
         
pdfStream.Close(true);


And my signature validation code :
Code
for (int i = 0; i < nbSigns; i++) {
   TElPDFSignature signature   = pdfStream.GetSignatureEntry(i);
   String signingTime      = dateFormat.format(signature.GetSigningTime());
               
   AppletAWS.println("Vérification de la signature n°" + (i + 1) + " : ");
   AppletAWS.println("\t- date : " + signingTime);
   sign.setDateSignature(signingTime);
   
   try {
      if (!signature.Validate()) {
         throw new SignatureInvalidAlteredDataException();
      }
                  
      AppletAWS.println("\t- état : valide");
                  
      this.fireStatus(this._fileSigned.getName(), Constantes.SIGN_VALID);
      rapport.setMessage(AppletAWS.getLang("pkcs7.verif.success"));
                  
      this._signatureIsValid   = true;
      this._signatureStatus   = Constantes.SIGN_VALID;
   }
   catch (SignatureInvalidAlteredDataException e) {
      AppletAWS.println("\t- état : invalide");
      throw e;
   }
   catch (Exception e) {
      AppletAWS.println("\t- état : invalide");
      throw e;
   }
   
   /*
    * Certificate validation...
    */
}

Thank you !
#25567
Posted: 07/08/2013 07:09:27
by Vsevolod Ievgiienko (EldoS Corp.)

Please try to validate the signature using our sample from \secbboxjava\Samples\PDFBlackbox\PAdES folder. You should also refer to its code for details on how to retrieve the reason of validation failure (see RefreshSignatureInfo method in the sample).
#25585
Posted: 07/09/2013 08:49:12
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

Hi again !

Thanks for the last advice, my signature validation method is now up to date and works just fine.
But it seems that the code you gave me to create a TElX509Certificate from a X509Certificate doesn't really works. I mean, I can sign with this code but the signature validation fails all the time, with the message "Signature corrupted" (TSBCMSAdvancedSignatureValidity.casvSignatureCorrupted) and this even in the case I check the signature validity with your sample in \secbboxjava\Samples\PDFBlackbox\PAdES folder.

So I guess the only way to sign correctly is to use the TElWinCertStorage.GetSystemStores().Add("MY") to get the certificates since the sample can sign with no problem. Or maybe I've done something wrong ? (The code I use to sign is the same as the one in my last post on this thread (07/08/2013 13:49:38)).

Oh by the way, the TSBCMSAdvancedSignatureValidity that I get from the TElPDFAdvancedPublicKeySecurityHandler of the signature always tells me that the chain validation failed (with my SecureBlackBox test project, your sample and my applet). What does it mean ? Is it because I have neither trusted certificates, nor CRLs ?
#25586
Posted: 07/09/2013 08:55:12
by Vsevolod Ievgiienko (EldoS Corp.)

Please try to use TElWinCertStorage. We'll try to reproduce the problem with the above mentioned X509Certificate to TElX509Certificate conversion.
#25607
Posted: 07/10/2013 05:50:20
by Vsevolod Ievgiienko (EldoS Corp.)

Indeed the problem exists. Sorry for the inconveniences. Our cryptoprovider didn't take some JCE limitations into account.

The fix will be included into the next SecureBlackbox build.
#25628
Posted: 07/11/2013 03:00:16
by Mickaël Bénès (Standard support level)
Joined: 02/26/2013
Posts: 74

No problem, I'm glad to have found a bug. :P

Juste to know, do you have a release date for the next SecureBlackbox build ? Thanks.
Also by EldoS: CallbackProcess
A component to control process creation and termination in Windows and .NET applications.

Reply

Statistics

Topic viewed 2790 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!